<?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: Oliver Schmidt</title>
    <description>The latest articles on DEV Community by Oliver Schmidt (@codejet).</description>
    <link>https://dev.to/codejet</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%2F257742%2F37811cc5-720c-49d4-a624-3e1c6a01e952.jpg</url>
      <title>DEV Community: Oliver Schmidt</title>
      <link>https://dev.to/codejet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/codejet"/>
    <language>en</language>
    <item>
      <title>George and Robert walk into a bar...</title>
      <dc:creator>Oliver Schmidt</dc:creator>
      <pubDate>Sun, 14 Jul 2024 16:46:47 +0000</pubDate>
      <link>https://dev.to/codejet/george-and-robert-walk-into-a-bar-413e</link>
      <guid>https://dev.to/codejet/george-and-robert-walk-into-a-bar-413e</guid>
      <description>&lt;p&gt;&lt;em&gt;Update (October 19, 2025): Removed the historical sections about George Boole and Robert Recorde as they distracted from the main topic.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The title might sound like there is only a joke waiting here for you (an SEO desaster, I know). Sorry to disappoint. The story is that &lt;a href="https://en.wikipedia.org/wiki/George_Boole" rel="noopener noreferrer"&gt;George Boole&lt;/a&gt; gave us Boolean logic, &lt;a href="https://en.wikipedia.org/wiki/Robert_Recorde" rel="noopener noreferrer"&gt;Robert Recorde&lt;/a&gt; gave us the equals sign — and &lt;a href="https://tc39.es/ecma262/2021/" rel="noopener noreferrer"&gt;ES2021&lt;/a&gt; combined them into JavaScript's logical assignment operators.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Logical Assignment Operators
&lt;/h2&gt;

&lt;p&gt;Logical assignment operators are syntactic sugar in JavaScript that combine assignment (&lt;code&gt;=&lt;/code&gt;) with a logical (&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;) or nullish coalescing (&lt;code&gt;??&lt;/code&gt;) operator. There are three types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logical AND Assignment (&lt;code&gt;&amp;amp;&amp;amp;=&lt;/code&gt;): Assigns the value on the right to the variable on the left only if the left variable is truthy.&lt;/li&gt;
&lt;li&gt;Logical OR Assignment (&lt;code&gt;||=&lt;/code&gt;): Assigns the value on the right to the variable on the left only if the left variable is falsy.&lt;/li&gt;
&lt;li&gt;Nullish Coalescing Assignment (&lt;code&gt;??=&lt;/code&gt;): Assigns the value on the right to the variable on the left only if the left variable is &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Logical AND Assignment (&lt;code&gt;&amp;amp;&amp;amp;=&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;&amp;amp;&amp;amp;=&lt;/code&gt; operator is a shortcut for setting a variable's value only if it currently holds a truthy value. It's particularly useful in scenarios where an action should only proceed if a certain condition remains true.&lt;/p&gt;

&lt;p&gt;Example Use Case: Feature Toggle&lt;/p&gt;

&lt;p&gt;Imagine a scenario where certain features should only be enabled for administrators:&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;isAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAdmin&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;canAccessDashboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;canAccessDashboard&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAuthenticated&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canAccessDashboard&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true if user is authenticated, otherwise false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code snippet ensures that canAccessDashboard is only true if both isAdmin and user.isAuthenticated() are true, effectively guarding the feature behind two conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logical OR Assignment (&lt;code&gt;||=&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;The ||= operator allows you to assign a value to a variable if the variable currently holds a falsy value (e.g., null, undefined, 0, false, ""). This is incredibly useful for setting default values.&lt;/p&gt;

&lt;p&gt;Example Use Case: Setting Defaults&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;userSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Set default theme if none is specified&lt;/span&gt;
&lt;span class="nx"&gt;userSettings&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="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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userSettings&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="c1"&gt;// Outputs 'dark'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This operator is ideal for initializing variables that have not been set, ensuring that your application uses a sensible default without overwriting potentially meaningful falsy values like &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nullish Coalescing Assignment (&lt;code&gt;??=&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;??&lt;/code&gt; operator, known as the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing" rel="noopener noreferrer"&gt;nullish coalescing operator&lt;/a&gt;, is a relatively recent addition to programming languages. It's not a logical assignment operator in the strict sense, even though the &lt;a href="https://tc39.es/ecma262/2021/" rel="noopener noreferrer"&gt;ES2021 specification&lt;/a&gt; classifies it as such, since it's not based on a logical operator. Instead, its development is more closely tied to the practical needs of programming, particularly in handling &lt;code&gt;null&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt; values in a clean and predictable manner.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;??=&lt;/code&gt; operator is used to assign a value to a variable if and only if the variable is currently null or undefined. This is more precise than the &lt;code&gt;||=&lt;/code&gt; operator, which also considers other falsy values.&lt;/p&gt;

&lt;p&gt;Example Use Case: Configuration Defaults&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;??=&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Set default timeout if not specified, i.e. undefined, or null&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Outputs 0, preserving the explicitly set falsy value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This operator is particularly useful in configurations and settings where defaults should only fill in missing values without replacing other falsy but valid settings like &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Benefits and Considerations
&lt;/h2&gt;

&lt;p&gt;Using logical assignment operators, instead of &lt;code&gt;if&lt;/code&gt; or &lt;code&gt;ternary&lt;/code&gt; statements, reduces the amount of code you need to write, and can make your intentions clearer to other developers. As with many features, the key is to use these operators judiciously, especially when dealing with falsy values that are valid in your code's context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Note
&lt;/h2&gt;

&lt;p&gt;There are more assignment operators in JavaScript, like the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Left_shift_assignment" rel="noopener noreferrer"&gt;left shift assignment operator&lt;/a&gt; (&lt;code&gt;&amp;lt;&amp;lt;=&lt;/code&gt;). Those seem less widely applicable to me but might be worth another post at some point...&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Cover image on top by &lt;a href="https://www.freepik.com/free-vector/digital-binary-code-futuristic-background-coding-programming_58676904.htm#query=binary&amp;amp;position=1&amp;amp;from_view=keyword&amp;amp;track=sph&amp;amp;uuid=64340f9b-7de3-4599-a09b-14a9e5e2acc2" rel="noopener noreferrer"&gt;starline on Freepik&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>history</category>
      <category>booleans</category>
      <category>assignment</category>
    </item>
    <item>
      <title>:where() :is() my mind?</title>
      <dc:creator>Oliver Schmidt</dc:creator>
      <pubDate>Fri, 28 Jun 2024 14:54:17 +0000</pubDate>
      <link>https://dev.to/codejet/where-is-my-mind-15c9</link>
      <guid>https://dev.to/codejet/where-is-my-mind-15c9</guid>
      <description>&lt;p&gt;&lt;em&gt;Update (October 19, 2025): Removed the CSS Nesting section as it contained an inaccuracy about specificity behavior and distracted from the main topic of the post. Added practical use cases for &lt;code&gt;:is()&lt;/code&gt; and &lt;code&gt;:where()&lt;/code&gt; to the Complex Selectors section.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In CSS, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes" rel="noopener noreferrer"&gt;pseudo-classes&lt;/a&gt; like &lt;code&gt;:hover&lt;/code&gt; and &lt;code&gt;:first-child&lt;/code&gt; apply styles mostly based on an element's state or position. There are also "functional pseudo-classes," among which &lt;code&gt;:not&lt;/code&gt; is the oldest and very likely still the most well-known. However, &lt;code&gt;:is()&lt;/code&gt; and &lt;code&gt;:where()&lt;/code&gt; are two less popular ones that also allow for simplifying complex CSS selectors. In this post, I will explore how these pseudo-classes work.&lt;/p&gt;

&lt;p&gt;And if now you're still a bit curious about the title of this post, the pseudo-classes discussed give me a unique opportunity to reference &lt;a href="https://www.youtube.com/watch?v=OJ62RzJkYUo" rel="noopener noreferrer"&gt;The Pixies&lt;/a&gt; in a technical article...&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding &lt;code&gt;:is()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;:is()&lt;/code&gt; pseudo-class simplifies the process of writing complex selector patterns in CSS. The question whether you should be using such patterns in the first place is another one. I'm briefly gonna come back to that later. For now simply consider the following CSS rules where you want to apply the same styles to various elements within article sections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="nc"&gt;.example&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="nf"&gt;#unique&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;darkblue&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;Using &lt;code&gt;:is()&lt;/code&gt;, this can be streamlined into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="nd"&gt;:is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.example&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;#unique&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;darkblue&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 not only reduces redundancy but also enhances readability. But there is one more thing: it's important to understand how &lt;code&gt;:is()&lt;/code&gt; interacts with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity" rel="noopener noreferrer"&gt;CSS specificity&lt;/a&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  Specificity in &lt;code&gt;:is()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Specificity determines which styles are applied when more than one rule could apply to an element. It's calculated based on the types of selectors used in a CSS rule:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ID selectors are the most specific (count as 100).&lt;/li&gt;
&lt;li&gt;Class selectors (&lt;code&gt;.example&lt;/code&gt;), pseudo-classes (like &lt;code&gt;:disabled&lt;/code&gt;), and attribute selectors (like &lt;code&gt;a[href*="example"]&lt;/code&gt;) are less specific (count as 10 each).&lt;/li&gt;
&lt;li&gt;Type selectors (like &lt;code&gt;h1&lt;/code&gt;) and pseudo-elements (like &lt;code&gt;::first-line&lt;/code&gt;) are the least specific (count as 1 each).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When using the &lt;code&gt;:is()&lt;/code&gt; pseudo-class, the specificity of the &lt;code&gt;:is()&lt;/code&gt; selector itself is considered to be the specificity of the most specific selector inside its parentheses. This means that it adopts the highest specificity value from its arguments.&lt;/p&gt;

&lt;p&gt;In the example above, the specificity of the &lt;code&gt;:is()&lt;/code&gt; selector is determined by the highest specificity among the included selectors, which in this case is the ID selector &lt;code&gt;#unique&lt;/code&gt; with a specificity count of 100. Therefore, the entire rule &lt;code&gt;article :is(h1, .example, #unique) a&lt;/code&gt; will have a specificity count of 102 (100 from &lt;code&gt;#unique&lt;/code&gt;, 1 from &lt;code&gt;article&lt;/code&gt; and 1 from &lt;code&gt;a&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;This configuration means that even though &lt;code&gt;h1&lt;/code&gt; and &lt;code&gt;.example&lt;/code&gt; have lower individual specificities (1 for type selectors and 10 for class selectors, respectively), within the &lt;code&gt;:is()&lt;/code&gt; they effectively adopt the specificity of &lt;code&gt;#unique&lt;/code&gt;, which is 100.&lt;/p&gt;

&lt;p&gt;Consequently, any CSS rule targeting &lt;code&gt;article :is(h1, .example, #unique) a&lt;/code&gt; will have a higher specificity than other rules targeting &lt;code&gt;article h1 a&lt;/code&gt; or &lt;code&gt;article .example a&lt;/code&gt; alone, even if those rules are defined later in the CSS. This higher specificity applies unless those competing rules also include an ID selector or are within a higher specificity context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring &lt;code&gt;:where()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;:where()&lt;/code&gt; pseudo-class functions very similarly to &lt;code&gt;:is()&lt;/code&gt;, with one crucial difference: it has 0 specificity. Using the same set of selectors, we can rewrite the example like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="nd"&gt;:where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.example&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;#unique&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;darkblue&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;h3&gt;
  
  
  Specificity in &lt;code&gt;:where()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The specificity calculation for CSS rules using &lt;code&gt;:where()&lt;/code&gt; is straightforward. The original first rule, &lt;code&gt;article h1 a&lt;/code&gt;, has a specificity of 1 from the element selector &lt;code&gt;h1&lt;/code&gt; plus 1 from each of the element selectors (&lt;code&gt;article&lt;/code&gt; and &lt;code&gt;a&lt;/code&gt;), totaling a specificity of 3. In contrast, this rule inside &lt;code&gt;:where()&lt;/code&gt;, &lt;code&gt;article :where(h1) a&lt;/code&gt;, maintains a specificity of 2, which comes solely from the element selectors &lt;code&gt;article&lt;/code&gt; and &lt;code&gt;a&lt;/code&gt;. This is because the &lt;code&gt;:where(h1)&lt;/code&gt; part contributes zero to the specificity.&lt;/p&gt;

&lt;p&gt;Therefore, if both rules target the same &lt;code&gt;a&lt;/code&gt; within an &lt;code&gt;h1&lt;/code&gt; element within &lt;code&gt;article&lt;/code&gt;, the original rule with higher specificity will override the second rule. This setup illustrates how &lt;code&gt;:where()&lt;/code&gt; allows for the application of styles that remain easy to override, making it a potential choice for applying broad, default styles that can be easily customized or overridden elsewhere in the stylesheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complex Selectors in Modern CSS
&lt;/h2&gt;

&lt;p&gt;Earlier in this article, I hinted at the question of whether using complex CSS selectors is advisable in the first place. While they are powerful tools, they carry inherent challenges. It can be difficult to manage them in large projects, as they often lead to brittle CSS that is hard to refactor. And while modern browsers are optimized for CSS parsing, overly complex selectors can still impact rendering performance, particularly in large DOM structures. Additionally, managing specificity with complex selectors, as seen with &lt;code&gt;:is()&lt;/code&gt;, can become cumbersome. This often leads to &lt;a href="https://stuffandnonsense.co.uk/blog/css-specisithity" rel="noopener noreferrer"&gt;"specificity wars"&lt;/a&gt;, where styles unintentionally override each other due to conflicting specificity levels.&lt;/p&gt;

&lt;p&gt;The landscape of styling in web development has significantly evolved over the last decade. Several modern methodologies and tools allow you to build complex UIs while making it easier to avoid these pitfalls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://getbem.com/" rel="noopener noreferrer"&gt;BEM&lt;/a&gt; encourages a flat structure with minimal nesting and specificity, making styles easier to read and maintain. It significantly reduces the risk of unintended style overrides and enhances modularity.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/css-modules/css-modules" rel="noopener noreferrer"&gt;CSS Modules&lt;/a&gt; are particularly useful in component-based architectures like React or Vue, where they allow for the local scoping of CSS by automatically creating a unique class name for each style. This method avoids global scope issues and helps in maintaining modular and reusable components without the fear of styles bleeding across components.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/topics/css-in-js" rel="noopener noreferrer"&gt;CSS-in-JS&lt;/a&gt; also scopes styles to components, reducing global conflicts and specificity issues, and offers dynamic styling capabilities based on state or props.&lt;/li&gt;
&lt;li&gt;Utility-First frameworks, such as &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt;, provide a vast set of utility classes that can be composed directly in the HTML. This minimizes the need for custom CSS and complex selectors.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.uxpin.com/studio/blog/ui-component-library/" rel="noopener noreferrer"&gt;Component Libraries&lt;/a&gt; come with a set of pre-designed and pre-styled components that can be directly used in projects, though they can also be headless. They help standardize UI elements across applications and reduce the need for custom CSS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if complex selectors should be minimized, &lt;code&gt;:is()&lt;/code&gt; and &lt;code&gt;:where()&lt;/code&gt; remain useful in some cases. For instance, use &lt;code&gt;:where()&lt;/code&gt; for base styles or &lt;a href="https://frontendmasters.com/blog/the-coyier-css-starter/" rel="noopener noreferrer"&gt;starters&lt;/a&gt; that need to stay easy to override, and &lt;code&gt;:is()&lt;/code&gt; to group shared interaction states like &lt;code&gt;:hover&lt;/code&gt; and &lt;code&gt;:focus&lt;/code&gt; without repetition.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Cover image on top by &lt;a href="https://unsplash.com/photos/program-script-digital-wallpaper-_yMciiStJyY?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Maik Jonietz on Unsplash&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>specificity</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Time, Space and Complexity</title>
      <dc:creator>Oliver Schmidt</dc:creator>
      <pubDate>Wed, 17 Apr 2024 15:43:37 +0000</pubDate>
      <link>https://dev.to/codejet/time-space-and-complexity-blo</link>
      <guid>https://dev.to/codejet/time-space-and-complexity-blo</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Big O Notation&lt;/li&gt;
&lt;li&gt;Time Complexity: The Speed of Execution&lt;/li&gt;
&lt;li&gt;Space Complexity: The Memory Usage&lt;/li&gt;
&lt;li&gt;Tail Call Optimization: A Special Case&lt;/li&gt;
&lt;li&gt;Dynamic Programming: A Potential Optimizer&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In my &lt;a href="https://dev.to/codejet/of-recursion-and-backtracking-3jhg"&gt;previous article on recursion and backtracking&lt;/a&gt;, we delved into a coding kata, exploring both a pure recursive solution and a dynamic programming approach. To keep the focus on understanding these concepts, I sidestepped the realm of time and space complexity for the most part. These are important aspects when evaluating the efficiency of algorithms, and while they were silently at work in the examples I discussed, they didn't take the spotlight. Now, it's time to bring these to the forefront.&lt;/p&gt;

&lt;p&gt;Admittedly, discussing the time and space complexity of solutions to a coding kata might seem a bit contrived, as these considerations typically come into play for more complex tasks, such as developing sophisticated algorithms. Yet, it provides an opportunity to explain these concepts in a more accessible context.&lt;/p&gt;

&lt;p&gt;And while the title might also suggest a foray into astrophysics, rest assured, we'll be sticking to the realm of computer science. The only space we'll be exploring is the one in your computer's memory...&lt;/p&gt;

&lt;h2&gt;
  
  
  Big O Notation
&lt;/h2&gt;

&lt;p&gt;Before we dive into the complexities of the pure recursive and dynamic programming solutions, let's take a moment to understand &lt;a href="https://en.wikipedia.org/wiki/Big_O_notation"&gt;Big O notation&lt;/a&gt;. Now, my own background in computer science isn't steeped in formal education, and I understand that many of you might be in the same boat. So, I won't - and frankly, couldn't - dive too deep into its formal definitions and mathematical underpinnings.&lt;/p&gt;

&lt;p&gt;Big O notation is a way to express the efficiency of an algorithm in terms of both time and space. The "O" in the notation stands for "Order of", and it's used to describe how the resource requirements of an algorithm grow as the size of the input increases. In the context of the kata example, this means that &lt;code&gt;n&lt;/code&gt; - which represents the number of parentheses we need to balance - is getting larger.&lt;/p&gt;

&lt;p&gt;When we talk about the number of operations an algorithm performs, we're discussing its time complexity. In the context of algorithmic analysis, "operations" refer to the fundamental steps to solve a problem, such as comparisons, arithmetic operations, or assigning values.&lt;/p&gt;

&lt;p&gt;Similarly, when we consider the amount of memory an algorithm uses, we're referring to its space complexity.&lt;/p&gt;

&lt;p&gt;The expression inside the parentheses, such as &lt;code&gt;O(1)&lt;/code&gt;, &lt;code&gt;O(n)&lt;/code&gt;, or &lt;code&gt;O(n^2)&lt;/code&gt;, describes the relationship between the size of the input (usually denoted as 'n') and the resource being measured. For example, &lt;code&gt;O(1)&lt;/code&gt; indicates constant time or space, meaning the algorithm's performance or memory usage does not change with the size of the input. &lt;code&gt;O(n)&lt;/code&gt; suggests linear growth, and &lt;code&gt;O(n^2)&lt;/code&gt; indicates quadratic growth, which can quickly become inefficient as the input size grows.&lt;/p&gt;

&lt;p&gt;When discussing the efficiency of algorithms, it's also useful to be aware of the term "&lt;a href="https://en.wikipedia.org/wiki/Polynomial"&gt;polynomial&lt;/a&gt; complexity", which applies to both time and space requirements. And here we have to get a bit more mathematical I'm afraid.&lt;br&gt;
Polynomial complexity is represented as &lt;code&gt;O(n^k)&lt;/code&gt;, where &lt;code&gt;n&lt;/code&gt; is the size of the input and &lt;code&gt;k&lt;/code&gt; is a fixed number known as the constant exponent. This means that the time or space needed by the algorithm grows at a rate proportional to the input size &lt;code&gt;n&lt;/code&gt; raised to the power of &lt;code&gt;k&lt;/code&gt;. This is generally more manageable than exponential complexity, such as &lt;code&gt;O(2^n)&lt;/code&gt;, where the resources needed can increase dramatically with the size of the input. Lower-degree polynomial complexities, like linear &lt;code&gt;O(n)&lt;/code&gt; or quadratic &lt;code&gt;O(n^2)&lt;/code&gt;, are usually efficient for large inputs. However, as the degree of the polynomial (&lt;code&gt;k&lt;/code&gt;) increases, the resource requirements grow accordingly, which can lead to decreased efficiency for very large inputs. Despite this, polynomial complexities are often sought after in the design of algorithms because they offer a reasonable compromise between the ability to handle complex problems and maintaining computational practicality.&lt;/p&gt;

&lt;p&gt;Here is a visualization of the efficiency of different algorithmic complexities, as referenced from the &lt;a href="https://www.bigocheatsheet.com"&gt;Big O Cheat Sheet&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx3abympp3pmb4eclg2w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx3abympp3pmb4eclg2w.png" alt="Big O Complexities" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For those interested in exploring further, you can find more examples of common function orders &lt;a href="https://en.wikipedia.org/wiki/Big_O_notation#Orders_of_common_functions"&gt;here&lt;/a&gt;. But be aware that most of these examples are quite mathematical in nature.&lt;/p&gt;

&lt;p&gt;It's important to note that Big O notation describes the upper limit of the resource usage in the worst-case scenario. An algorithm with a time complexity of &lt;code&gt;O(n)&lt;/code&gt; might not always take exactly &lt;code&gt;n&lt;/code&gt; steps to complete, and one with a space complexity of &lt;code&gt;O(n)&lt;/code&gt; might not use exactly &lt;code&gt;n&lt;/code&gt; units of memory, but these are the maximums we can expect.&lt;/p&gt;

&lt;p&gt;To determine the complexity of a given algorithm, you need to analyze both the operations it performs and the memory it utilizes, as these factors contribute to its time and space complexity, respectively. For instance, if an algorithm processes each element of an input array once, its time complexity is &lt;code&gt;O(n)&lt;/code&gt;, where n is the size of the array. Conversely, if the algorithm must allocate an additional array of the same size, its space complexity would also be &lt;code&gt;O(n)&lt;/code&gt;. If the algorithm compares each element with every other element, resulting in nested loops, its time complexity becomes &lt;code&gt;O(n^2)&lt;/code&gt;, reflecting the &lt;code&gt;n^2&lt;/code&gt; pairs of comparisons for an array of size &lt;code&gt;n&lt;/code&gt;. Similarly, if the algorithm needs to store a unique result for each pair, the space complexity would also be &lt;code&gt;O(n^2)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In practice, determining an algorithm's complexity is often a multifaceted task that extends beyond mere operation counts. It requires a deep understanding of the algorithm's structure, mathematical analysis, and occasionally, advanced concepts from theoretical computer science, such as the properties of specific number sequences like &lt;a href="https://en.wikipedia.org/wiki/Catalan_number"&gt;Catalan numbers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And now, a word of caution regarding what follows below...&lt;/strong&gt; As I'm neither a computer scientist nor mathematician, I consulted Large Language Models (&lt;a href="https://en.wikipedia.org/wiki/Large_language_model"&gt;LLMs&lt;/a&gt;) to analyze the algorithms and determine the time and space complexity of both the pure recursive and dynamic programming solutions. While LLMs can provide educated estimates, they are &lt;a href="https://en.wikipedia.org/wiki/Hallucination_(artificial_intelligence)"&gt;not perfect&lt;/a&gt;. The complexities provided by these models are based on my careful questioning of them. Despite my best efforts to extract accurate information, I cannot guarantee the absolute correctness of these complexities. Therefore, the results should be considered a helpful reference for understanding the performance of these solutions rather than an indisputable fact.&lt;/p&gt;
&lt;h2&gt;
  
  
  Time Complexity: The Speed of Execution
&lt;/h2&gt;

&lt;p&gt;Time complexity refers to how the duration of an algorithm's execution grows with the increase in the size of the input. As mentioned above, it's usually expressed using Big O notation.&lt;/p&gt;

&lt;p&gt;Consider the &lt;a href="https://dev.to/codejet/of-recursion-and-backtracking-3jhg/#the-kata"&gt;pure recursive solution from my previous article&lt;/a&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;balancedParens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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;n&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="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="dl"&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;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&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;generate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&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;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;open&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;close&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;close&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;close&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="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;generate&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&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 function systematically explores each possibility for arranging &lt;code&gt;n&lt;/code&gt; pairs of parentheses through recursive calls. The time complexity for this algorithm is &lt;code&gt;O(4^n / sqrt(n))&lt;/code&gt;. But what does this mean without getting into the weeds of mathematics?&lt;/p&gt;

&lt;p&gt;In the simplest terms, the &lt;code&gt;4^n&lt;/code&gt; part of &lt;code&gt;O(4^n / sqrt(n))&lt;/code&gt; suggests that the number of different combinations the function has to check is growing exponentially - every time we add another pair of parentheses, the number of possibilities multiplies. However, the division by &lt;code&gt;sqrt(n)&lt;/code&gt; (the &lt;a href="https://en.wikipedia.org/wiki/Square_root"&gt;square root&lt;/a&gt; of &lt;code&gt;n&lt;/code&gt;) indicates that this growth is somewhat offset as &lt;code&gt;n&lt;/code&gt; gets larger. Altogether, we can consider this complexity to be similar to &lt;code&gt;O(2^n)&lt;/code&gt; as explained and visualized above.&lt;/p&gt;

&lt;p&gt;To illustrate with examples, let's look at the cases where &lt;code&gt;n = 1&lt;/code&gt; and &lt;code&gt;n = 2&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For &lt;code&gt;n = 1&lt;/code&gt;, there's only one pair of parentheses to place, resulting in just one combination: &lt;code&gt;()&lt;/code&gt;. The time complexity for this specific case is &lt;code&gt;O(4^1 / sqrt(1))&lt;/code&gt;, which calculates to &lt;code&gt;O(4)&lt;/code&gt;. This indicates that the function will perform 4 operations when there is only one pair of parentheses.&lt;/li&gt;
&lt;li&gt;For &lt;code&gt;n = 2&lt;/code&gt;, there are two pairs of parentheses, which can be arranged in two ways: &lt;code&gt;(())&lt;/code&gt; and &lt;code&gt;()()&lt;/code&gt;. The time complexity for this specific case is &lt;code&gt;O(4^2 / sqrt(2))&lt;/code&gt;, which simplifies to &lt;code&gt;O(16 / 1.41)&lt;/code&gt;, or approximately &lt;code&gt;O(11.31)&lt;/code&gt;. In this instance, the function is expected to perform roughly 11 operations, which is more than double the operations for &lt;code&gt;n = 1&lt;/code&gt;, illustrating the exponential increase in the number of operations as &lt;code&gt;n&lt;/code&gt; increases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember, these calculations are approximations meant to give you a sense of how the function's runtime grows. They're not exact figures, but they help us understand the efficiency without diving into complex math.&lt;/p&gt;

&lt;p&gt;It's natural to wonder if a different approach could yield better performance or complexity. However, the time complexity of generating all combinations of balanced parentheses is inherently exponential. This is because there are &lt;code&gt;2^(2n)&lt;/code&gt; combinations in total. Therefore, achieving a polynomial time complexity for this problem is not possible. This is a fundamental aspect of the problem itself, not a limitation of the specific approach used. So, while we can strive to optimize our solution as much as possible, we cannot escape the exponential nature of this problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Space Complexity: The Memory Usage
&lt;/h2&gt;

&lt;p&gt;While time complexity gives us an idea of how long an algorithm will take, space complexity tells us how much memory it will use. Just like time complexity, space complexity can be expressed using Big O notation, which helps us understand how memory usage grows with the size of the input. When analyzing the space complexity of an algorithm, it is important to consider both the auxiliary space and the space used by the input.&lt;/p&gt;

&lt;p&gt;Auxiliary space is the additional memory that an algorithm uses beyond the input size. This includes memory allocated for variables, data structures, and the stack frames in recursive calls. This space is temporary and can be reclaimed after the algorithm's execution.&lt;/p&gt;

&lt;p&gt;The space used by the input refers to the memory occupied by the input data itself, which remains constant for a given set of inputs and does not change with the algorithm's internal workings. When comparing the space complexity of two algorithms, the size of the input is often similar, which allows the space used by the input to be disregarded for the comparison.&lt;/p&gt;

&lt;p&gt;Consequently, the comparison focuses on the auxiliary space, which can vary based on the algorithm's implementation and is subject to optimization. Therefore, while the total space used by an algorithm includes both auxiliary space and the space used by the input, space complexity analysis and comparisons between algorithms typically emphasize the auxiliary space.&lt;/p&gt;

&lt;p&gt;In the case of the pure recursive solution, the space complexity is &lt;code&gt;O(n)&lt;/code&gt;. This is because the maximum number of frames, or layers, on the call stack at any point is proportional to the number of pairs of parentheses &lt;code&gt;n&lt;/code&gt;. However, the actual maximum height of the call stack will be &lt;code&gt;2n&lt;/code&gt; due to the nature of the problem, where we must place &lt;code&gt;n&lt;/code&gt; opening and &lt;code&gt;n&lt;/code&gt; closing parentheses to form a valid combination. For a detailed illustration of how the call stack changes during the execution of the pure recursive solution, please refer to the &lt;a href="https://dev.to/codejet/of-recursion-and-backtracking-3jhg/#walkthrough"&gt;walkthrough section of my previous article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Each recursive call to &lt;code&gt;generate&lt;/code&gt; adds a new frame to the call stack, which includes the function's local variables, parameters, and return address. The memory used by these frames accumulates, contributing to the total space complexity of the algorithm. This is why deep recursion can lead to high memory usage, and in extreme cases, a stack overflow error if the call stack exceeds the amount of memory allocated to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tail Call Optimization: A Special Case
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Tail_call"&gt;Tail call&lt;/a&gt; optimization (TCO) is a technique that can improve the performance of recursive functions, particularly in terms of space complexity. In a tail-recursive function, the recursive call is the last operation in the function. This means that when the function makes the recursive call, it doesn't need to do any more computation after the call returns. Some programming languages or compilers can optimize these calls to avoid adding a new stack frame for each call, which can significantly reduce the space complexity and prevent stack overflow issues.&lt;/p&gt;

&lt;p&gt;However, the support for TCO varies across different programming languages. Languages like Scheme, Haskell, and Scala have full support for TCO, meaning they can optimize any tail-recursive function. On the other hand, languages like Python and Java do not support TCO.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://262.ecma-international.org/6.0/"&gt;ECMAScript 2015&lt;/a&gt; (ES6) standard introduced the concept of "proper tail calls" (PTC), which mandates that compliant JavaScript engines &lt;em&gt;must&lt;/em&gt; implement TCO for tail calls. PTC ensures that a function call in tail position does not increase the call stack size, thus allowing for potentially infinite recursive calls in constant stack space.&lt;/p&gt;

&lt;p&gt;Despite being part of the ES6 specification, the adoption of PTC in JavaScript engines is very limited. As of now, JavaScriptCore, the engine behind WebKit browsers like Safari, is the only engine that fully supports PTC (available in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode"&gt;strict mode&lt;/a&gt;). V8, which powers Chrome and Node.js, had implemented PTC but ultimately decided against shipping the feature. More information on the decision can be found in the &lt;a href="https://v8.dev/blog/modern-javascript#proper-tail-calls"&gt;V8 blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/tc39/proposal-ptc-syntax"&gt;proposal of "syntactic tail calls"&lt;/a&gt; to provide an explicit syntax for tail calls, co-championed by committee members from Mozilla (responsible for &lt;a href="https://en.wikipedia.org/wiki/SpiderMonkey"&gt;SpiderMonkey&lt;/a&gt;, the engine of Firefox) and Microsoft, was a response to these concerns. However, this proposal is now listed among the TC39's &lt;a href="https://github.com/tc39/proposals/blob/main/inactive-proposals.md"&gt;inactive proposals&lt;/a&gt;, possibly due to diminished interest, which may stem from the infrequent use of tail recursive functions in JavaScript.&lt;/p&gt;

&lt;p&gt;In the absence of widespread engine-level support for PTC, developers have explored language-level solutions to achieve tail call optimization. The &lt;a href="[http://glat.info/fext/](http://glat.info/fext/)"&gt;fext.js&lt;/a&gt; library offers a method for managing tail calls in JavaScript, while the &lt;a href="[https://github.com/krzkaczor/babel-plugin-tailcall-optimization](https://github.com/krzkaczor/babel-plugin-tailcall-optimization)"&gt;Babel plugin for tail call optimization&lt;/a&gt; provides transformations for tail-recursive functions during the build process. These tools are also not widely adopted though.&lt;/p&gt;

&lt;p&gt;The original pure recursive solution, as shown above, is not tail-recursive because it does not return the result of the recursive call directly. Instead, the function concludes with the operation of returning the final result, &lt;em&gt;after&lt;/em&gt; all recursive calls have been made and their outcomes have been aggregated.&lt;/p&gt;

&lt;p&gt;To illustrate a tail-recursive style, we can rewrite it:&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;function&lt;/span&gt; &lt;span class="nf"&gt;balancedParens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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;n&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="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="dl"&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;generate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&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;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&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;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;open&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;open&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;close&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&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;close&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;close&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;result&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;result&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="nf"&gt;generate&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="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 this version, the result array is passed through each call to &lt;code&gt;generate&lt;/code&gt;, and the function is structured to return the result of the recursive call directly whenever possible. Should PTC be available in the execution environment, the space complexity would be reduced to &lt;code&gt;O(1)&lt;/code&gt;. This is because the same stack frame would be reused for each recursive call, which eliminates the need for additional memory for each call and maintains a constant stack depth. In any case, it's good to be aware of this technique when working with recursive functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic Programming: A Potential Optimizer
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://dev.to/codejet/of-recursion-and-backtracking-3jhg/#bonus-pure-recursion-vs-dynamic-programming"&gt;dynamic programming solution to the parentheses problem&lt;/a&gt; incrementally builds solutions for larger sets of parentheses, such as &lt;code&gt;()()&lt;/code&gt;, based on the solutions for smaller sets, like &lt;code&gt;()&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balancedParens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="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="dl"&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;let&lt;/span&gt; &lt;span class="nx"&gt;parentheses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;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;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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;left&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;balancedParens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="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;right&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;balancedParens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;parentheses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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;left&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;right&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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;parentheses&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 method uses memoization to store solutions to previously solved subproblems, enhancing efficiency by avoiding redundant calculations. This is an improvement over the pure recursive approach, which recalculates solutions for each subproblem. And, while theoretically being more space-intensive than pure recursion, the use of memoization is justified by gains in computational speed, especially for larger problems.&lt;/p&gt;

&lt;p&gt;The efficiency of our dynamic programming solution is captured by the time complexity &lt;code&gt;O(n^2 * C_n)&lt;/code&gt;. In this formula, &lt;code&gt;C_n&lt;/code&gt; stands for the nth Catalan number. Now, the &lt;a href="https://en.wikipedia.org/wiki/Catalan_number"&gt;Catalan number&lt;/a&gt; for a specific &lt;code&gt;n&lt;/code&gt; tells us how many different ways we can arrange &lt;code&gt;n&lt;/code&gt; pairs of balanced parentheses. It's a special sequence of numbers that &lt;a href="https://en.wikipedia.org/wiki/Eug%C3%A8ne_Charles_Catalan"&gt;Eugène Charles Catalan&lt;/a&gt; figured out follows a particular pattern, making it easier to predict the number of arrangements without having to list them all out. You can use a &lt;a href="https://www.123calculus.com/en/catalan-number-page-1-16-200.html"&gt;Catalan number calculator&lt;/a&gt; to verify this.&lt;/p&gt;

&lt;p&gt;To give a practical example of how &lt;code&gt;O(n^2 * C_n)&lt;/code&gt; plays out, let's consider &lt;code&gt;n = 2&lt;/code&gt; again, which means we're looking for combinations of two pairs of parentheses: &lt;code&gt;(())&lt;/code&gt; and &lt;code&gt;()()&lt;/code&gt;. The Catalan number for &lt;code&gt;n = 2&lt;/code&gt; is 2, reflecting these two possibilities. Now, if we plug &lt;code&gt;n = 2&lt;/code&gt; into our time complexity formula, we square the &lt;code&gt;n&lt;/code&gt; to get &lt;code&gt;4&lt;/code&gt;, and then multiply by the Catalan number, which gives us &lt;code&gt;4 * 2 = 8&lt;/code&gt;. So, for &lt;code&gt;n = 2&lt;/code&gt;, the dynamic programming solution is expected to perform roughly 8 operations to find all valid combinations. This is in contrast to the pure recursive approach, which doesn't remember past solutions and would perform more operations as &lt;code&gt;n&lt;/code&gt; increases.&lt;/p&gt;

&lt;p&gt;Regarding space complexity, the dynamic programming solution requires storage for each unique combination of balanced parentheses it computes. The amount of storage correlates with the nth Catalan number for each &lt;code&gt;n&lt;/code&gt;, leading to a space complexity of &lt;code&gt;O(n * C_n)&lt;/code&gt;. This stands in comparison to the pure recursive approach’s space complexity of &lt;code&gt;O(n)&lt;/code&gt;, attributed to the recursion stack’s depth. While the dynamic programming method requires more space due to memoization.&lt;/p&gt;

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

&lt;p&gt;While recursive solutions can be simple and elegant, they may be inefficient in terms of time complexity due to redundant calculations and can also consume significant memory with deep call stacks.&lt;/p&gt;

&lt;p&gt;Tail call optimization can improve the space efficiency of some recursive functions, but it's not universally applicable and is not supported by all programming languages or compilers.&lt;/p&gt;

&lt;p&gt;Dynamic programming can optimize time complexity by eliminating redundant work, but this often comes at the cost of increased space complexity due to storing subproblem results. Additionally, dynamic programming can be more complex and harder to understand than pure recursion.&lt;/p&gt;

&lt;p&gt;Theoretically, the choice between using pure recursion or dynamic programming depends on the nature of the task at hand and the constraints one is facing, particularly whether optimizing for time or space is more critical. In reality, it's probably mostly a matter of experience or preference. Usually, only if issues arise do we think about our solutions more formally. And even then, most programmers do not typically apply Big O notation, unless they are working on something significant, like the React DOM diffing algorithm maybe. Instead, we measure actual performance to pinpoint bottlenecks. But a prior awareness of time and space complexity &lt;em&gt;can&lt;/em&gt; certainly be valuable here. And if we want or have to take it a step further, leveraging LLMs can assist us in determining the complexity of a given solution, as well as helping us find a more performant one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Cover image on top by &lt;a href="https://unsplash.com/photos/galaxy-digital-wallpaper-rCbdp8VCYhQ?utm_content=creditShareLink&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash"&gt;Andy Holmes on Unsplash&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>algorithms</category>
      <category>performance</category>
      <category>programming</category>
    </item>
    <item>
      <title>Of recursion and backtracking</title>
      <dc:creator>Oliver Schmidt</dc:creator>
      <pubDate>Tue, 12 Dec 2023 10:22:15 +0000</pubDate>
      <link>https://dev.to/codejet/of-recursion-and-backtracking-3jhg</link>
      <guid>https://dev.to/codejet/of-recursion-and-backtracking-3jhg</guid>
      <description>&lt;p&gt;&lt;em&gt;Update (December 17, 2023): Added a new paragraph in the section on dynamic programming to provide a more balanced view of its trade-offs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update (January 18, 2024): Updated the dynamic programming section with a solution using proper memoization, and revised the explanation accordingly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update (January 19, 2024): Added tiny optimization for the n = 0 case in the recursive solution, which I had forgotten there.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update (February 20, 2024): Made a small improvement in the dynamic programming section.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Recursion and Backtracking&lt;/li&gt;
&lt;li&gt;The Call Stack&lt;/li&gt;
&lt;li&gt;The Kata&lt;/li&gt;
&lt;li&gt;Walkthrough&lt;/li&gt;
&lt;li&gt;Bonus: Pure Recursion vs. Dynamic Programming&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Recently, I was working on a coding &lt;a href="https://en.wikipedia.org/wiki/Kata#Outside_martial_arts" rel="noopener noreferrer"&gt;kata&lt;/a&gt; on &lt;a href="http://codewars.com" rel="noopener noreferrer"&gt;codewars.com&lt;/a&gt;. Early on, I started thinking that a potential solution might utilize recursion, a concept that involves a function calling itself. However, I quickly realized that my grasp of recursion was not as solid as it needed to be for this task. In this post, I will share the insights gained from deepening my understanding of recursion while working through the kata.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recursion and Backtracking
&lt;/h2&gt;

&lt;p&gt;Recursion and the related concept of backtracking are techniques in computer science used to solve complex problems by breaking them down into simpler subproblems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Recursion_(computer_science)" rel="noopener noreferrer"&gt;Recursion&lt;/a&gt; involves a function calling itself with different arguments until it reaches a so called &lt;a href="https://en.wikipedia.org/wiki/Recursion#base_case" rel="noopener noreferrer"&gt;base case&lt;/a&gt;. The base case is a condition that signals the function to stop calling itself and start returning. It's the simplest possible version of the problem, one that can be solved directly without any further recursive calls. The base case is crucial in recursion as it prevents infinite recursion and allows the function to terminate at a certain point. We will revisit this concept in the practical part of this article, which should provide a clearer understanding of what it means and how it works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Backtracking" rel="noopener noreferrer"&gt;Backtracking&lt;/a&gt;, on the other hand, involves exploring all possible solutions to a problem and, when a dead end is reached, "backtracking" to a previous step and trying a different path. These techniques are often used in combination to solve problems in areas such as &lt;a href="https://en.wikipedia.org/wiki/Combinatorics" rel="noopener noreferrer"&gt;combinatorics&lt;/a&gt;, parsing, and artificial intelligence. They're particularly useful for problems where the solution involves exploring all possible combinations or &lt;a href="https://en.wikipedia.org/wiki/Permutation" rel="noopener noreferrer"&gt;permutations&lt;/a&gt; of a set of elements.&lt;/p&gt;

&lt;p&gt;One prominent example of a task that can be effectively solved using recursion is the mathematical puzzle known as the &lt;a href="https://en.wikipedia.org/wiki/Tower_of_Hanoi" rel="noopener noreferrer"&gt;Tower(s) of Hanoi&lt;/a&gt;. It involves moving a stack of disks from one peg to another following certain rules. Notably, Douglas Crockford referenced this puzzle in his book &lt;a href="https://www.oreilly.com/library/view/javascript-the-good/9780596517748/" rel="noopener noreferrer"&gt;"JavaScript: The Good Parts"&lt;/a&gt; to explain recursion.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Call Stack
&lt;/h2&gt;

&lt;p&gt;In JavaScript, the &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Call_stack" rel="noopener noreferrer"&gt;call stack&lt;/a&gt; is a key component of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop" rel="noopener noreferrer"&gt;event loop&lt;/a&gt;, which is the engine that drives JavaScript's single-threaded, non-blocking, asynchronous behavior. The call stack, recursion, and backtracking are all interconnected. When a function is called in JavaScript, it's added (or "pushed") onto the call stack. If that function calls another function, the new function is pushed onto the top of the stack and becomes the currently executing function. This "Last In, First Out" (LIFO) structure of the call stack is what allows recursion to work. Each recursive call adds a new layer to the stack, and when a base case is reached, the functions start returning and are "popped off" the stack one by one. This is where backtracking comes into play, allowing the program to explore different paths or solutions. The event loop continuously checks the call stack and processes functions based on the LIFO principle. Once the stack is empty, it means that all functions have finished executing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Kata
&lt;/h2&gt;

&lt;p&gt;To better understand how these techniques work in practice, let's take a closer look at the aforementioned &lt;a href="https://www.codewars.com/kata/5426d7a2c2c7784365000783" rel="noopener noreferrer"&gt;kata&lt;/a&gt; which involves generating all possible combinations of a set of parens:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Write a function which makes a list of strings representing all of the ways you can balance n pairs of parentheses.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
balancedParens(0) =&amp;gt; [""]&lt;br&gt;
balancedParens(1) =&amp;gt; ["()"]&lt;br&gt;
balancedParens(2) =&amp;gt; ["()()","(())"]&lt;br&gt;
balancedParens(3) =&amp;gt; ["()()()","(())()","()(())","(()())","((()))"]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As hinted at above, this is a classic example of a problem that can be solved using recursion and backtracking.&lt;/p&gt;

&lt;p&gt;Our strategy will be to build all combinations of parentheses from scratch, starting with an empty string and adding one parenthesis at a time. We'll keep track of the number of open and close parentheses we've added so far to ensure that we only add valid combinations.&lt;/p&gt;

&lt;p&gt;To do this, we'll use a recursive function, which we'll call &lt;code&gt;generate&lt;/code&gt;. This function will take the current combination of parentheses, and the number of open and close parentheses.&lt;/p&gt;

&lt;p&gt;The function will add an open parenthesis if we haven't used up all the open parentheses, and a close parenthesis if it doesn't exceed the number of open parentheses. This ensures that we don't end up with any unbalanced combinations like &lt;code&gt;((())&lt;/code&gt;.&lt;br&gt;
If we've used up all the open and close parentheses, we have a valid combination, which we'll add to our list. If not, we'll continue to add parentheses by making recursive calls to &lt;code&gt;generate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;codwars provides an empty &lt;code&gt;balancedParens&lt;/code&gt; function accepting one argument, &lt;code&gt;n&lt;/code&gt;, representing the pairs of parenthesis to balance. We're gonna put our &lt;code&gt;generate&lt;/code&gt; function inside of it:&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;function&lt;/span&gt; &lt;span class="nf"&gt;balancedParens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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;n&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="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="dl"&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;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&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;generate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&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;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;open&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;close&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;close&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;close&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="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;generate&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&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;h2&gt;
  
  
  Walkthrough
&lt;/h2&gt;

&lt;p&gt;Now, let's walk through the process of how this function works in the context of the kata, using a simple visualization of the call stack. This will give us a clear, step-by-step understanding of how recursion and backtracking unfold in real time.&lt;/p&gt;

&lt;p&gt;As to not have too many explanatory steps, but enough to be clear, I'm gonna focus on the &lt;code&gt;n = 2&lt;/code&gt; case.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Step
&lt;/h3&gt;

&lt;p&gt;The initial call to the recursive function &lt;code&gt;generate&lt;/code&gt; is made with an empty string: &lt;code&gt;generate("", 0, 0)&lt;/code&gt;. This pushes a new frame onto the call stack. The previously empty stack now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- generate("", 0, 0);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;result&lt;/code&gt; array is &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Step
&lt;/h3&gt;

&lt;p&gt;This leads to a recursive call with an open parenthesis added: &lt;code&gt;generate("(", 1, 0)&lt;/code&gt;. This pushes another frame onto the stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- generate("(", 1, 0)
  - generate("", 0, 0);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;result&lt;/code&gt; array is still &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Step
&lt;/h3&gt;

&lt;p&gt;This call can lead to two recursive calls: one where another open parenthesis is added &lt;code&gt;generate("((", 2, 0)&lt;/code&gt; and one where a close parenthesis is added &lt;code&gt;generate("()", 1, 1)&lt;/code&gt;. Let's follow the first call where another open parenthesis is added: &lt;code&gt;generate("((", 2, 0)&lt;/code&gt;. This pushes another frame onto the stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- generate("((", 2, 0)
  - generate("(", 1, 0)
    - generate("", 0, 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;result&lt;/code&gt; array is still &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Step
&lt;/h3&gt;

&lt;p&gt;Now, we can only add close parentheses. The next call is &lt;code&gt;generate("(()", 2, 1)&lt;/code&gt;. This pushes another frame onto the stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- generate("(()", 2, 1)
  - generate("((", 2, 0)
    - generate("(", 1, 0)
      - generate("", 0, 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;result&lt;/code&gt; array is still &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Step
&lt;/h3&gt;

&lt;p&gt;Finally, we add another close parenthesis: &lt;code&gt;generate("(())", 2, 2)&lt;/code&gt;. This pushes another frame onto the stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- generate("(())", 2, 2)
  - generate("(()", 2, 1)
    - generate("((", 2, 0)
      - generate("(", 1, 0)
        - generate("", 0, 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've reached a valid combination &lt;code&gt;"(())"&lt;/code&gt;, which is added to the &lt;code&gt;result&lt;/code&gt; array. The &lt;code&gt;result&lt;/code&gt; array is now &lt;code&gt;["(())"]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the &lt;strong&gt;base case&lt;/strong&gt; where the current combination of parentheses has reached the length of &lt;code&gt;2 * n&lt;/code&gt; (since each pair of parentheses contributes two characters to the string). When this condition is met, we know we've added all the parentheses we can, and we add the current combination to the &lt;code&gt;result&lt;/code&gt; array. This is why we check if &lt;code&gt;current.length === 2 * n&lt;/code&gt; at the beginning of each call to generate. If this condition is true, we've reached the base case, and we add current to result and return from the function. This is the point at which we stop making new recursive callsfor the current combination and start backtracking.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Step
&lt;/h3&gt;

&lt;p&gt;We have now explored all combinations starting with two open parentheses. The call &lt;code&gt;generate("(())", 2, 2)&lt;/code&gt; finishes, so its frame is popped from the stack. The stack now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- generate("(()", 2, 1)
  - generate("((", 2, 0)
    - generate("(", 1, 0)
      - generate("", 0, 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;result&lt;/code&gt; array is still &lt;code&gt;["(())"]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Step
&lt;/h3&gt;

&lt;p&gt;Control returns to the previous call, which was &lt;code&gt;generate("(()", 2, 1)&lt;/code&gt;. In this call, we've already explored the possibility of adding a close parenthesis (which led to the valid combination &lt;code&gt;"(())"&lt;/code&gt;), so we can't do anything more here. The function finishes and its frame is popped from the stack. The stack now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- generate("((", 2, 0)
  - generate("(", 1, 0)
    - generate("", 0, 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;result&lt;/code&gt; array is still &lt;code&gt;["(())"]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Step
&lt;/h3&gt;

&lt;p&gt;Control returns to the previous call, which was &lt;code&gt;generate("((", 2, 0)&lt;/code&gt;. In this call, we've already explored the possibility of adding a closing parenthesis (which led to the string &lt;code&gt;"(()"&lt;/code&gt;), so we can't do anything more here. The function finishes and its frame is popped from the stack. The stack now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- generate("(", 1, 0)
  - generate("", 0, 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;result&lt;/code&gt; array is still &lt;code&gt;["(())"]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Step
&lt;/h3&gt;

&lt;p&gt;Control returns to the previous call, which was &lt;code&gt;generate("(", 1, 0)&lt;/code&gt;. In this call, we've already explored the possibility of adding an open parenthesis (which led to the string &lt;code&gt;"(("&lt;/code&gt;), so now we add a close parenthesis and call &lt;code&gt;generate("()", 1, 1)&lt;/code&gt; to explore this new possibility. This pushes another frame onto the stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- generate("()", 1, 1)
  - generate("(", 1, 0)
    - generate("", 0, 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;result&lt;/code&gt; array is still &lt;code&gt;["(())"]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Step
&lt;/h3&gt;

&lt;p&gt;From here, we can add an open parenthesis: &lt;code&gt;generate("()(", 2, 1)&lt;/code&gt;. This pushes another frame onto the stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- generate("()(", 2, 1)
  - generate("()", 1, 1)
    - generate("(", 1, 0)
      - generate("", 0, 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;result&lt;/code&gt; array is still &lt;code&gt;["(())"]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  11. Step
&lt;/h3&gt;

&lt;p&gt;Finally, we add a close parenthesis: &lt;code&gt;generate("()()", 2, 2)&lt;/code&gt;. This pushes another frame onto the stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- generate("()()", 2, 2)
  - generate("()(", 2, 1)
    - generate("()", 1, 1)
      - generate("(", 1, 0)
        - generate("", 0, 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've reached another valid combination &lt;code&gt;"()()"&lt;/code&gt;, which is added to the result array. The &lt;code&gt;result&lt;/code&gt; array is now &lt;code&gt;["(())", "()()"]&lt;/code&gt;. Once again, this is a &lt;strong&gt;base case&lt;/strong&gt; where the current combination of parentheses has reached the length of 2*n.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Steps
&lt;/h3&gt;

&lt;p&gt;The function continues to backtrack, popping off all remaining items from the call stack as there are no further valid combinations remaining. Each pop corresponds to a return from a recursive call, indicating that all combinations starting with the current set of parentheses have been fully explored.&lt;/p&gt;

&lt;p&gt;After all the remaining items have been popped off the stack, the outer function has completed its task. It then returns the result array, marking the end of the process and the completion of the task.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;This step-by-step walkthrough illustrates how recursion and backtracking work together to solve the problem. The recursive function &lt;code&gt;generate&lt;/code&gt; explores all possible combinations of parentheses, while the call stack keeps track of the different combinations we're exploring. When we've explored all combinations starting with a certain prefix, we backtrack by returning from the current call and popping its frame from the stack. This allows us to explore other combinations starting with a different prefix.&lt;/p&gt;

&lt;p&gt;There are also neat tools like &lt;a href="http://latentflip.com/loupe/" rel="noopener noreferrer"&gt;latentflip.com/loupe/&lt;/a&gt;, &lt;a href="https://www.jsv9000.app/" rel="noopener noreferrer"&gt;www.jsv9000.app&lt;/a&gt; and &lt;a href="http://pythontutor.com/javascript.html" rel="noopener noreferrer"&gt;pythontutor.com/javascript.html&lt;/a&gt; that allow you to step through the execution of code and provide visualizations at each step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Pure Recursion vs. Dynamic Programming
&lt;/h2&gt;

&lt;p&gt;While this article focuses on recursion, it's important to note that recursion alone can sometimes lead to inefficiencies, especially when a function is called multiple times with the same arguments, leading to redundant computations. This happens because a purely recursive solution doesn't store the results of subproblems, so each time a subproblem is encountered, it's solved from scratch.&lt;/p&gt;

&lt;p&gt;However, purely recursive solutions can be simpler to understand and implement, especially for problems that are naturally suited to recursion. They can also be more intuitive, as they often closely mirror the problem's definition. For example, consider a recursive function to calculate the &lt;a href="https://en.wikipedia.org/wiki/Fibonacci_sequence" rel="noopener noreferrer"&gt;Fibonacci&lt;/a&gt; sequence. The problem's definition naturally lends itself to a recursive solution: the nth Fibonacci number is the sum of the (n-1)th and (n-2)th Fibonacci numbers.&lt;/p&gt;

&lt;p&gt;But this recursive solution can lead to inefficiencies. To calculate the 5th Fibonacci number, the function needs to calculate the 4th and 3rd Fibonacci numbers. To calculate the 4th Fibonacci number, it needs to calculate the 3rd and 2nd Fibonacci numbers. Notice that the 3rd Fibonacci number is calculated twice. As the input size increases, the number of redundant calculations grows exponentially, leading to poor performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Dynamic_programming" rel="noopener noreferrer"&gt;Dynamic programming&lt;/a&gt; is a strategy that can help overcome this inefficiency. It solves complex problems by breaking them down into simpler subproblems, solving each subproblem only once, and storing the results of these subproblems to avoid redundant work. This is where memoization comes in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Memoization" rel="noopener noreferrer"&gt;Memoization&lt;/a&gt; is a technique often used in dynamic programming to optimize the computation time of recursive functions. It works by storing the results of (expensive) function calls and reusing them when the same inputs occur again. However, it's important to note that to avoid unexpected behavior and bugs, memoization should generally only be used with &lt;a href="https://en.wikipedia.org/wiki/Pure_function" rel="noopener noreferrer"&gt;pure functions&lt;/a&gt;, or functions that behave like pure functions for the range of inputs you're interested in.&lt;/p&gt;

&lt;p&gt;Here's a dynamic programming solution to the parentheses kata:&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;function&lt;/span&gt; &lt;span class="nf"&gt;balancedParens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="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="dl"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&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;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&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;parentheses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;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;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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;left&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;balancedParens&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;memo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;balancedParens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&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;memo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;parentheses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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;left&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;right&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="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parentheses&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;parentheses&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 solution still utilizes recursion to break the problem down into smaller subproblems. However, it differs from a pure recursive solution in how it uses the results of these subproblems. Instead of solving the same subproblem multiple times, it solves each subproblem only once and stores the results for future use. This approach eliminates the need for backtracking and can be more efficient in terms of the call stack, as the function is only called once for each unique value of &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's consider the parentheses task with &lt;code&gt;n&lt;/code&gt; being &lt;code&gt;2&lt;/code&gt;. The initial call to the function is &lt;code&gt;balancedParens(2)&lt;/code&gt;, which checks the &lt;code&gt;memo&lt;/code&gt; object to see if the result for &lt;code&gt;n = 2&lt;/code&gt; has already been computed. If not, it initializes an empty array parentheses and enters a loop that will iterate &lt;code&gt;n&lt;/code&gt; times.&lt;/p&gt;

&lt;p&gt;On the first iteration, the function makes two nested calls to &lt;code&gt;balancedParens&lt;/code&gt;, with arguments &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;, respectively. Since these calls have not been made before, their results are computed and stored in the &lt;code&gt;memo&lt;/code&gt; object. The function then generates new combinations by inserting a pair of parentheses around each combination from the &lt;code&gt;n = 0&lt;/code&gt; array and appending each combination from the &lt;code&gt;n = 1&lt;/code&gt; array. These new combinations are added to the &lt;code&gt;parentheses&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;The function continues to iterate, generating all combinations for &lt;code&gt;n = 2&lt;/code&gt;, until it has explored all possibilities and returns the &lt;code&gt;parentheses&lt;/code&gt; array, which is also stored in the &lt;code&gt;memo&lt;/code&gt; object for &lt;code&gt;n = 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The key point here is that each unique call to &lt;code&gt;balancedParens(i, memo)&lt;/code&gt; and &lt;code&gt;balancedParens(n - 1 - i, memo)&lt;/code&gt; within the loop is computed only once for each unique value of &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;n - 1 - i&lt;/code&gt;. The memoization ensures that the results of these calls are stored and then reused in the nested for loops to generate all combinations of parentheses. This is the essence of dynamic programming: solving each subproblem once, storing the result, and reusing it to avoid redundant work.&lt;/p&gt;

&lt;p&gt;While dynamic programming can offer benefits in terms of reducing redundant computations, it's important to note that it may increase memory usage due to the need to store intermediate results. For the problem at hand, the dynamic programming solution with memoization should outperform the pure recursive solution in terms of speed of execution, as it avoids recalculating the same subproblems. But this likely comes at the cost of higher memory usage. I've chosen to include the dynamic programming solution to provide a fuller picture of the different strategies that can be used to tackle this problem and to illustrate the concept of dynamic programming in a practical context.&lt;/p&gt;

&lt;p&gt;I also openly admit that, for me, comprehending the dynamic programming solution presents a greater challenge compared to the purely recursive solution. The complexity introduced by the nested loops, along with the need to correctly handle the left and right conditions, adds layers of difficulty that make the solution harder to grasp.&lt;/p&gt;

&lt;p&gt;I recommend using the tools mentioned earlier to get a similar step-by-step walkthrough of this solution, as it provides valuable insights into how the function builds up the solutions for values of n to generate all combinations of well-formed parentheses.&lt;/p&gt;

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

&lt;p&gt;Recursion and backtracking are powerful tools in a programmer's toolkit, capable of tackling complex problems with elegant solutions. Understanding these concepts, along with related concepts like the call stack and dynamic programming, can help you write more efficient and effective code. Whether you're generating combinations of parentheses, solving a puzzle, or traversing a tree, recursion and backtracking can often provide the solution you need.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Cover image on top by &lt;a href="https://unsplash.com/photos/timelapse-photography-of-light-PIOgkhaF3WA?utm_content=creditShareLink&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Tine Ivanič on Unsplash&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>algorithms</category>
      <category>programming</category>
    </item>
    <item>
      <title>Cassette tapes, a pseudo degree, and open source software: an interview with Andrea Giammarchi</title>
      <dc:creator>Oliver Schmidt</dc:creator>
      <pubDate>Sun, 08 Nov 2020 16:13:43 +0000</pubDate>
      <link>https://dev.to/codejet/cassette-tapes-a-pseudo-degree-and-open-source-software-an-interview-with-andrea-giammarchi-17he</link>
      <guid>https://dev.to/codejet/cassette-tapes-a-pseudo-degree-and-open-source-software-an-interview-with-andrea-giammarchi-17he</guid>
      <description>&lt;p&gt;Andrea Giammarchi aka WebReflection (&lt;a href="https://webreflection.medium.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;, &lt;a href="https://twitter.com/webreflection" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;) is a very prolific open source creator. Even if you don't know him or one of his &lt;a href="https://github.com/WebReflection" rel="noopener noreferrer"&gt;projects&lt;/a&gt; (yet), you might have used some of his work. His &lt;a href="https://github.com/WebReflection/document-register-element" rel="noopener noreferrer"&gt;document-register-element&lt;/a&gt; polyfill is being used by &lt;a href="https://github.com/ampproject/amphtml" rel="noopener noreferrer"&gt;Google AMP HTML&lt;/a&gt;, and his virtual DOM alternative called &lt;a href="https://github.com/WebReflection/hyperHTML" rel="noopener noreferrer"&gt;hyperHTML&lt;/a&gt; by &lt;a href="https://github.com/w3c/respec" rel="noopener noreferrer"&gt;W3C's ReSpec&lt;/a&gt;, for example. &lt;/p&gt;

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

&lt;p&gt;If you look at his Github, you might wonder how he finds time for anything else but creating software. Yet, he was kind enough to answer a few questions that I sent him.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hey Andrea, thanks a lot for taking the time for this! How are you doing lately, during these rather "interesting" times? I suppose you've also been working from home a lot?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hi Oliver, before answering these questions, I'd like to thank you for this opportunity to talk a bit about myself. Hoping somebody else is also interested :-)&lt;/p&gt;

&lt;p&gt;These are rather interesting times indeed. But as I've been working remotely for the last 2 years and a half, I've been lucky enough to not feel or perceive too many changes in my daily routine. One thing I’m missing is traveling, 'cause I do love traveling. But during 2020 it obviously hasn't been possible with the same freedom and tranquillity I used to have. Accordingly, I'm doing just fine, and luckily enough my family, friends, and relatives are also fine. But I can't wait for things to go back to as normal as possible, for me and everyone else, too!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, to go back all to the way to the beginning: what was your first contact with computers (including things like gaming consoles)?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you like a bit of time traveling: I was born in 1978, and what we call consoles nowadays were fully programmable computers with a keyboard and optionally a joystick. My first "console" was an &lt;a href="https://en.wikipedia.org/wiki/MSX" rel="noopener noreferrer"&gt;MSX&lt;/a&gt;, which was programmed in a specialized version of BASIC. And instead of a hard disk and/or an optical drive, it was running games through &lt;a href="https://en.wikipedia.org/wiki/Cassette_tape" rel="noopener noreferrer"&gt;cassette tapes&lt;/a&gt;. And that with an analog quality so unpredictable, that most of the time I had to wait for absurd noises playing for minutes, just to have nothing on the screen in the end. Imagine a missed semicolon in a huge JS project, which is able to break everything. Now imagine all bytes being passed along through tape... Yeah, that's how old I am, and that was my first experience with computers.&lt;/p&gt;

&lt;p&gt;Thanks gosh, not so long after, I had a "proper" &lt;a href="https://en.wikipedia.org/wiki/Intel_80386" rel="noopener noreferrer"&gt;386SX&lt;/a&gt; PC. And yet I was super envious about the quality of &lt;a href="https://en.wikipedia.org/wiki/Amiga" rel="noopener noreferrer"&gt;Amiga&lt;/a&gt; games.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Was it already this initial contact that led to you being interested in programming, or how/when/why did you get started with it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My first attempt at writing software in &lt;a href="https://en.wikipedia.org/wiki/BASIC" rel="noopener noreferrer"&gt;BASIC&lt;/a&gt; was close to an epic fail: I spent almost 2 hours just to make the "teapot" program run. And that only to realize that once successfully compiled, those dozen lines of code were there only to play a teapot-like sound instead of showing a teapot on the screen. Well, it sucks when you are like 12 and feel like you just wasted 2 hours for a bleep. It made literally no sense. But I still blame myself for never trying harder between back then and 1998, when my interest in programming reappeared. That was because of the internet, which became kinda usable in Italy. And, of course, since I discovered the internet, I've mostly been focused on web and networking-related software.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Did you then get an education in computer science/information technology? If so what/where exactly?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a funny part of my history. Technically I do have a B.Sc. degree in Computer Science. But practically I never finished my studies. I studied Software Engineering at my local hometown University in Italy, but its program was already "centuries-old" compared to what I could study or learn online. And the web was not part of any university program. It has been valuable to learn basics about the C programming language and Java, understand databases and the file system. But I was already working full time as a Certified Zend Engineer PHP developer, also using MySQL and XSLT/XHTML. So, working and studying in parallel didn't really end up well. But I also wasn't learning anything new or useful at university, due to its outdated software engineering program.&lt;/p&gt;

&lt;p&gt;However, when I've got my H1-B visa to work in California, my 12+ years of experience were validated as the equivalent of a B.Sc. degree in Computer Science by the &lt;a href="https://www.linkedin.com/school/baruch-college/" rel="noopener noreferrer"&gt;Baruch College, City University of New York (CUNY)&lt;/a&gt;. So, that's how I've got my pseudo-degree after studying at two different universities, without ever completing my studies there (I'm still learning daily though).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And how did you end up working primarily with frontend technologies?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ahh, this is a kinda common assumption about me, and I tell you why it’s inaccurate: I've been doing mostly backend, tooling, database, or Linux-related development way more than I've done frontend. And I'm also currently working on a specialized core technology that rarely sees the light of the known frontend. However, if there's one thing I've learned since 1998, it's that any great backend means nothing without a great frontend able to consume it. Which is why I've learned ActionScript 1/2/3, XSLT/XHTML/HTML/CSS, and last but not least, JS, in order to be able to offer any possible backend to consumers. In 2009, for example, I've worked on the core engine that was fueling Nokia HTML5 mobile maps. But before that, I was doing mostly PHP, Java, or C#, plus frontend on top. And right now I'm doing 99% of JavaScript, without touching the HTML/CSS side of the web equation. However, not only have I fun working with web technologies, I've been doing what today is known as full stack development for about forever. And I think everyone else should also try to play around with the whole stack, including Linux bits and bobs, instead of sticking only with the frontend. Because the potentials unleashed by knowing more about the stack are unimaginable!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You have a host of projects on Github. Where does all the inspiration come from, or what is your main motivation? Do you read specs a lot (I think I saw you commenting on some threads regarding ES standards)?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;More than an inspired developer, I tend to be a problem solver. And here's my usual thinking: I need X, let's see if anyone did X before... OK, tons of Y, but really, nobody wrote X... Here we go, I've published X.&lt;/p&gt;

&lt;p&gt;It might look like I have some &lt;a href="https://en.wikipedia.org/wiki/Not_invented_here" rel="noopener noreferrer"&gt;NIH&lt;/a&gt; syndrome, but the truth is that I tend to need essential stuff, while many projects out there often provide too much.&lt;/p&gt;

&lt;p&gt;I also usually have close to 100% code coverage, which results in close to 0 bugs on my projects. But that's not always the case for software already out there... So, that's me: minimalistic requirements and needs well addressed by a plethora of tiny libraries that share most of the core code but do one thing only. And to reach these results, I gotta read specs, of course. Otherwise, I end up with the feeling that I'm using some library or technology of which I don't really understand how it works behind the scenes. And that's a no-go for me in general.&lt;/p&gt;

&lt;p&gt;But surely enough, the open source community is the biggest source of inspiration to me. And indeed, all I am trying to do with my libraries and software is to pay back what open source gave me since the beginning of my journey. I feel indebted to it. I try to respect credits, sponsor open source projects, and use as much Open Source as I can, providing helpers whenever there's a tiny gap to fill, even in the ArchLinux community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What was the most fun project to work on and why? Or, alternatively, which is your favorite project, and why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As tech requirements and capabilities change at "light speed" in the web industry, this question is very hard to answer. As a problem solver, and from time to time also as a pioneer of new ideas, I don't have absolute favorite projects. I just have projects that have been my favorite during the time I worked on or needed those projects. For example, the Canvas-based HTML5 map in 2009 was my favorite challenge. But so was the &lt;a href="https://github.com/twitter/twemoji" rel="noopener noreferrer"&gt;twemoji&lt;/a&gt; library I've written in 2014, and then &lt;a href="https://github.com/WebReflection/hyperHTML" rel="noopener noreferrer"&gt;hyperHTML&lt;/a&gt; in 2017, and now &lt;a href="https://github.com/WebReflection/uhtml" rel="noopener noreferrer"&gt;uhtml&lt;/a&gt;, &lt;a href="https://github.com/WebReflection/uce" rel="noopener noreferrer"&gt;uce&lt;/a&gt;, and &lt;a href="https://github.com/WebReflection/uce-template" rel="noopener noreferrer"&gt;uce-template&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But then again, I've recently investigated a bit if there was any IoT-based intranet solution to collect all the pictures and videos I record during my trips. And after some underwhelming search results, I've created myself a software called &lt;a href="https://github.com/WebReflection/life-diary" rel="noopener noreferrer"&gt;Life Diary&lt;/a&gt;. It works even on my older Raspberry Pi laying around my flat, providing EXIF manipulation, data correlation, and more, to my own personal media without changing quality or metadata. It's also visualizing a handy map per each place I visited.&lt;/p&gt;

&lt;p&gt;That project also raised a requirement, an offline geo location search and reverse geocode, but since nothing was available out there, I've created the &lt;a href="https://github.com/WebReflection/geo2city" rel="noopener noreferrer"&gt;geo2city&lt;/a&gt; module, which does just that and nothing else. And it still performs well on the previously mentioned Raspberry Pi, hence it's suitable for any other web-based service, too.&lt;/p&gt;

&lt;p&gt;That's it: my favorite project is usually the one I'm working on right now. Either at work or as a side project, as long as it satisfies my requirements and it didn't exist before me trying to find a solution. But I can eventually list successful favorite projects from my past, including that HTML5 map I've already mentioned, &lt;a href="https://github.com/twitter/twemoji" rel="noopener noreferrer"&gt;twemoji&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/flatted" rel="noopener noreferrer"&gt;flatted&lt;/a&gt; the successor of CircularJSON, everything based on string literals I've worked on 'till now, and all the ArchLinux/ARM installers and helpers I've created to date. Or NodeJS projects such as &lt;a href="https://github.com/WebReflection/electroff" rel="noopener noreferrer"&gt;electroff&lt;/a&gt;, usable even via the Hardware Accelerated &lt;a href="https://wpewebkit.org/" rel="noopener noreferrer"&gt;WPEWebKit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If I'm not mistaken, you have voiced some frustration over the fact that a lot of developers seem to favor certain "custom solutions" over leveraging standards. &lt;a href="http://webreflection.blogspot.com/2015/04/the-dom-is-not-slow-your-abstraction-is.html" rel="noopener noreferrer"&gt;"The DOM is not slow, your abstraction is"&lt;/a&gt; is one article in which you touched upon this. Could you further elaborate on the whole topic?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's quite an old post of mine, but it often comes up for one reason or another. So, thanks for asking! The whole point of that post is that way too often developers pick the latest greatest fuzzed solution, believing it's a must use. Even for tasks that are probably covered by it but are likely 1/10th of the things such a solution can do... Remember me being minimalistic about software? That's my point. If you use a library that does a hundred things, but all you have to do is to quickly update a generic table, like the one used in the good ole DBMonster benchmark case, are you sure you're using the right tool for the job? Developers rarely complain about the library they chose, but are far too easy in blaming the underlying technology. But if you really know the underlying technology, why aren't you using it in the first place to obtain the best performance for a specific task? And if you don't fully know or understand this underlying layer, how can you blame it for being slow? Or how is your library of choice bypassing such "slowness"?&lt;/p&gt;

&lt;p&gt;In a few words, I was a bit tired of reading DOM-related rants on Twitter, when literally every library based on the Web platform uses the DOM. So, claiming that library X is faster than the DOM has always been nonsense to me. Learn "vanilla JS" first, find where a library can help according to the task at hand, and use such library instead of picking some famous one even just to simply display content that any static HTML could’ve served, you know what I mean?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speaking of which: what are some of the most underused standards/technologies/tools in your opinion? And in turn, what are some of the most overused ones?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;IMHO, the most underused technology these days are standards in general. It looks like everyone is trying hard to avoid what the platform has to offer natively, which is awesome already, bypassing it through some shiny tool, library, or indirection, that hides that power behind the scenes. And please don't get me wrong, I love the plethora of helpers, libraries, frameworks, and solutions to every possible task that the open source community offers these days, web-related or not. But I just wish more developers would pick smaller and less bloated solutions before using, like, 200kb to bootstrap a static page. Pick the right tool for the job, and feel free to do some refactoring if requirements or complexity change, as opposed to picking something that solves everything, even for the most basic task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Since you have such broad and deep knowledge, did you never consider becoming more of an educator? Like offering courses on Udemy or Egghead, or even outside of these platforms, like quite a few people are doing now (and pretty successfully so, it seems). Or maybe creating a business around one or multiple of your projects (the other day I read that &lt;a href="https://adamwathan.me/tailwindcss-from-side-project-byproduct-to-multi-mullion-dollar-business/" rel="noopener noreferrer"&gt;Tailwind UI has become a multi-million dollar business&lt;/a&gt;, for example)?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Well, during 2015 I've tried to be a freelancer, mostly focused on technical web training in London. But besides London being a super competitive city, I can tell you without shame that I've failed at that. I had a few customers, and as far as I know, they were all happy with my training.&lt;br&gt;
I've also written &lt;a href="https://leanpub.com/jsglossary" rel="noopener noreferrer"&gt;a tiny book&lt;/a&gt; that was probably targeting the wrong audience. And yet, not only couldn't I promote myself enough to reach more customers, 'cause I suck at marketing in general, but I do love creating, solving, and writing code. And teaching requires a huge amount of work that could very easily backfire in terms of time investment vs. results.&lt;/p&gt;

&lt;p&gt;That being said, I might try again to start some more concrete training online. But I think the market is already saturated. So, I'm not sure my current skills would be as useful in that field, as compared to producing new ideas or software, as I’ve been doing to date.&lt;/p&gt;

&lt;p&gt;There are also many speakers better than me. I think I've learned that knowledge or experience doesn't easily or necessarily translate into good teaching, 'cause there are too many factors to consider... Although, I also rarely give up on something. So, who knows ;-)&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>webstandards</category>
      <category>interview</category>
    </item>
    <item>
      <title>Adding a contact form to a static site using Netlify Functions</title>
      <dc:creator>Oliver Schmidt</dc:creator>
      <pubDate>Sun, 26 Jul 2020 16:16:34 +0000</pubDate>
      <link>https://dev.to/codejet/adding-a-contact-form-to-a-static-site-using-netlify-functions-35j8</link>
      <guid>https://dev.to/codejet/adding-a-contact-form-to-a-static-site-using-netlify-functions-35j8</guid>
      <description>&lt;p&gt;That you can spice up a static site with dynamic functionality using so-called serverless functions is not that new anymore. Many have probably first learned about them through &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/welcome.html" rel="noopener noreferrer"&gt;AWS Lambda functions&lt;/a&gt;. But they are not tied to any specific cloud provider:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Conventionally, serverless functions are single-purpose, programmatic functions that are hosted on managed infrastructure. These functions, which are invoked through the Internet, are hosted and maintained by cloud computing companies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.pubnub.com/blog/what-is-a-serverless-function/" rel="noopener noreferrer"&gt;What is a Serverless Function?&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you are hosting any of your projects on Netlify, you can use their offering which is simply called &lt;a href="https://www.netlify.com/products/functions/" rel="noopener noreferrer"&gt;functions&lt;/a&gt;. One interesting bit here is that they are actually AWS Lambda functions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Netlify lets you deploy serverless Lambda functions without an AWS account, and with function management handled directly within Netlify. Your serverless functions are version-controlled, built, and deployed along with the rest of your Netlify site, and we will automatically handle service discovery through our built-in API gateway.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, Netlify abstracts some of the complexity around AWS Lambda away for you, and thus makes it very easy to get started with serverless functions. Also, their free tier is pretty generous.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;For this post, I'm assuming you have a running &lt;a href="https://www.gatsbyjs.org/" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt; site hosted on Netlify to which you want to add a contact form. This implies that you are familiar with React, particularly with functional components and hooks, and also &lt;a href="https://yarnpkg.com/" rel="noopener noreferrer"&gt;Yarn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm going to explain how to set up Sendgrid as the service provider and create a serverless function that is calling their API when your contact form is submitted.&lt;/p&gt;

&lt;p&gt;If you are using a different &lt;a href="https://www.staticgen.com/" rel="noopener noreferrer"&gt;static site generator&lt;/a&gt; and/or another transactional email service (Mailgun, Mailjet, etc.), this post should still help you with understanding how to create a contact form using Netlify functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signing up for Sendgrid
&lt;/h2&gt;

&lt;p&gt;If you don't have one already, you need to create a &lt;a href="https://sendgrid.com/" rel="noopener noreferrer"&gt;Sendgrid&lt;/a&gt; account. Their free plan currently allows you to send 40,000 emails during the first 30 days. After this period you can still send 100 emails per day "forever". This should be more than enough for running a contact form on a small private site.&lt;/p&gt;

&lt;p&gt;Just go to &lt;a href="https://signup.sendgrid.com/" rel="noopener noreferrer"&gt;https://signup.sendgrid.com/&lt;/a&gt; and follow the instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sendgrid Web API
&lt;/h2&gt;

&lt;p&gt;What allows us to send our contact form using a serverless function is Sendgrid's Web API. It supports several programming languages, including the one we want: Node.js. You can directly navigate to &lt;a href="https://app.sendgrid.com/guide/integrate/langs/nodejs" rel="noopener noreferrer"&gt;https://app.sendgrid.com/guide/integrate/langs/nodejs&lt;/a&gt; which outlines the process for using the API with Node.js:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make sure you have Node.js installed&lt;/li&gt;
&lt;li&gt;Create an API key&lt;/li&gt;
&lt;li&gt;Create an environment variable&lt;/li&gt;
&lt;li&gt;Install the package&lt;/li&gt;
&lt;li&gt;Send your first email&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'm assuming you already have Node.js installed. So, as a first step you have to enter a name for your API key. That name is not overly important, simply choose something that makes sense to you. Once you did that, hit the &lt;code&gt;Create Key&lt;/code&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flu0u414evt0ipj8gbd2x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flu0u414evt0ipj8gbd2x.png" alt="Creating an API key in Sendgrind"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, the next step says you should create an environment variable for the key. But we're gonna come back to that later and instead continue with installing the Sendgrid npm package.&lt;/p&gt;

&lt;p&gt;Inside your project folder run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;yarn&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;sendgrid&lt;/span&gt;&lt;span class="sr"&gt;/mai&lt;/span&gt;&lt;span class="err"&gt;l
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final step contains the code for sending a message to their API using that npm package. It's pretty simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// using Twilio SendGrid's v3 Node.js Library&lt;/span&gt;
&lt;span class="c1"&gt;// https://github.com/sendgrid/sendgrid-nodejs&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sgMail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;@sendgrid/mail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;sgMail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setApiKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SENDGRID_API_KEY&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;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sending with Twilio SendGrid is Fun&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;and easy to do anywhere, even with Node.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;strong&amp;gt;and easy to do anywhere, even with Node.js&amp;lt;/strong&amp;gt;&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;sgMail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But before we can actually make our first call, we have to do a few more things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Netlify CLI
&lt;/h2&gt;

&lt;p&gt;When I was looking for information on how to add a contact form to my Gatsby site on Netfliy, I only found solutions involving &lt;a href="https://github.com/netlify/netlify-lambda" rel="noopener noreferrer"&gt;netlify-lambda&lt;/a&gt;. But if you don't need a build-step for your function, like when you are using TypeScript, then you can achieve the same in a simpler way using &lt;a href="https://github.com/netlify/cli" rel="noopener noreferrer"&gt;Netlify Dev&lt;/a&gt;. More about the differences between these two tools can be found in the &lt;a href="https://github.com/netlify/netlify-lambda#when-to-use-netlify-dev-or-netlify-lambda-or-both" rel="noopener noreferrer"&gt;netlify-lambda docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since Netlify Dev comes as part of &lt;a href="https://cli.netlify.com/" rel="noopener noreferrer"&gt;Netfliy CLI&lt;/a&gt;, you have to install it globally first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;yarn&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="nx"&gt;netlify&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;cli&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also do this using Homebrew, if you're on a Mac:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;brew&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;netlify&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;cli&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating evironment variables in Netlify
&lt;/h2&gt;

&lt;p&gt;Especially if you commit your code into a public repo, you don't want your API key to be visible there. A common way to keep confidential information out of your code is to store it in environment variables.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Environment variables are variables external to our application which reside in the OS or the container of the app is running in. An environment variable is simply a name mapped to a value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackabuse.com/managing-environment-variables-in-node-js-with-dotenv/" rel="noopener noreferrer"&gt;Managing Environment Variables in Node.js with dotenv&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, we're gonna store them directly in Netlify, which is the production environment.&lt;/p&gt;

&lt;p&gt;When you are logged in to Netlify, go to &lt;code&gt;Settings &amp;gt; Build &amp;amp; Deploy &amp;gt; Environment&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fubi4tfz2j0rjc0zg8q7z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fubi4tfz2j0rjc0zg8q7z.png" alt="Form for setting environment variables in Netlify"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have to add two variables: &lt;code&gt;SENDGRID_API_KEY&lt;/code&gt; and &lt;code&gt;SENDGRID_TO_EMAIL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add the API key you generated earlier as the value of &lt;code&gt;SENDGRID_API_KEY&lt;/code&gt;, and the email address to which the messages from the contact form should be delivered as the value of &lt;code&gt;SENDGRID_TO_EMAIL&lt;/code&gt;. Don't forget to save.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the environment variables available locally
&lt;/h2&gt;

&lt;p&gt;To test our code while developing, we also need to make the environment variables available locally. In &lt;a href="https://www.gatsbyjs.org/docs/environment-variables/#client-side-javascript" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt; we can do this by creating a &lt;code&gt;.env.development&lt;/code&gt; file. It contains the same keys and values you put into Netfliy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;SENDGRID_API_KEY="your_api_key"&lt;/span&gt;
&lt;span class="s"&gt;SENDGRID_TO_EMAIL="your_email@provider.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're gonna see how these are being accessed in the code of the function, which we are going to create next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the serverless function
&lt;/h2&gt;

&lt;p&gt;Now you have to create a new folder inside your &lt;code&gt;src&lt;/code&gt; folder, where the serverless function(s) are going to live. I named mine &lt;code&gt;functions&lt;/code&gt;, but it can be chosen freely. The latter also goes for the name of the file that holds your function.&lt;/p&gt;

&lt;p&gt;Here is the complete code:&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;envConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`.env.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&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;sgMail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;@sendgrid/mail&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SENDGRID_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SENDGRID_TO_EMAIL&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;event&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;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;sgMail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setApiKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SENDGRID_API_KEY&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;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SENDGRID_TO_EMAIL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`New message from yourdomain.com`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sgMail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&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;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;202&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Message sent&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="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="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;statusCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&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;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;code&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&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;statusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="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;Gatsby comes with a package called &lt;a href="https://www.npmjs.com/package/dotenv" rel="noopener noreferrer"&gt;dotenv&lt;/a&gt; that loads environment variables into Node's &lt;code&gt;process.env&lt;/code&gt;, which is &lt;a href="https://nodejs.org/docs/latest/api/process.html#process_process_env" rel="noopener noreferrer"&gt;"an object containing the user environment"&lt;/a&gt;. So if you don't use Gatsby, you might have to install it first.&lt;/p&gt;

&lt;p&gt;Accordingly, the first line of code uses &lt;code&gt;dotenv&lt;/code&gt; to load the &lt;code&gt;.env.development&lt;/code&gt; file we created earlier:&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;envConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`.env.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&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;After doing so, our environment variables are available as properties on &lt;code&gt;process.env&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SENDGRID_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SENDGRID_TO_EMAIL&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exporting a &lt;code&gt;handler&lt;/code&gt; method is a &lt;a href="https://docs.netlify.com/functions/build-with-javascript/#format" rel="noopener noreferrer"&gt;convention for Netlify functions&lt;/a&gt;. The one I defined is &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function" rel="noopener noreferrer"&gt;asynchronous&lt;/a&gt;. This is so that we can &lt;code&gt;await&lt;/code&gt; the result of the call to Sendgrid, which returns a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" rel="noopener noreferrer"&gt;Promise&lt;/a&gt;. The method will be provided three arguments:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Netlify provides the event and context parameters when the serverless function is invoked. You provide the callback parameter, which is optional, but recommended.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We only really need the &lt;code&gt;event&lt;/code&gt; parameter though, which provides us with the email and message entered into the contact form:&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;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apart from that, the function basically just contains the code we saw in Sendgrid earlier, combined with a &lt;code&gt;try/catch&lt;/code&gt; block for handling success and error cases when calling their API. In either case, an object with a &lt;code&gt;statusCode&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt; property is returned for use in the contact form.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Netlify
&lt;/h2&gt;

&lt;p&gt;To make Netlify aware of any functions existing in your codebase, you can either use the Netlify UI or the &lt;a href="https://docs.netlify.com/configure-builds/file-based-configuration/" rel="noopener noreferrer"&gt;file-based configuration&lt;/a&gt;. The latter works by placing a &lt;code&gt;netlify.toml&lt;/code&gt; config file at the root of your project, which is what I'm going to do here. In our case the content is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[build]&lt;/span&gt;
  &lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"yarn build"&lt;/span&gt;
  &lt;span class="py"&gt;functions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"src/functions/"&lt;/span&gt;
  &lt;span class="py"&gt;publish&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"public/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;command&lt;/code&gt; tells Netlify which command to use for running the build.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;functions&lt;/code&gt; contains the path to the functions folder that you created earlier. If you chose something else than &lt;code&gt;functions&lt;/code&gt;, you have to adapt the path accordingly.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;publish&lt;/code&gt; specifies where the output of the build process is supposed to be placed. For a Gatsby site, this is typically the &lt;code&gt;public&lt;/code&gt; folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the contact form
&lt;/h2&gt;

&lt;p&gt;With the function and configuration in place, we can now add the contact form. I placed it inside &lt;code&gt;src &amp;gt; components &amp;gt; ContactForm.js&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ContactForm&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="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;isPosting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsPosting&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;postingError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPostingError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;postingSuccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPostingSuccess&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;emailEl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRef&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;messageEl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRef&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;postMail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;emailEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messageEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&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="nf"&gt;setIsPosting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/.netlify/functions/sendmail&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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;application/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="na"&gt;body&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="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setPostingError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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="nf"&gt;setPostingSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setPostingError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setIsPosting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;handleSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;postMail&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;postingSuccess&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;SuccessMessage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt; &lt;span class="nx"&gt;sent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Thank&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SuccessMessage&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="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&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;Fieldset&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;Legend&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Contact&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Legend&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;Label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Your&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="o"&gt;*&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Label&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;Input&lt;/span&gt;
              &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your email address&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email address&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;emailEl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPosting&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;disabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;required&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;Label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Your&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;*&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Label&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;Textarea&lt;/span&gt;
              &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;messageEl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPosting&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;disabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;required&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;Button&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPosting&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;disabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;Send&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;/Fieldset&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;/form&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="nx"&gt;postingError&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;ErrorMessage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Something&lt;/span&gt; &lt;span class="nx"&gt;went&lt;/span&gt; &lt;span class="nx"&gt;wrong&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;please&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="nf"&gt;again &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;later&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;/ErrorMessage&amp;gt; : null&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a simple mail form with an email and message field defined as &lt;a href="https://reactjs.org/docs/uncontrolled-components.html" rel="noopener noreferrer"&gt;uncontrolled components&lt;/a&gt;. I'm not going to go into the specifics of the React code here as that's not the point of this post.&lt;/p&gt;

&lt;p&gt;The important bit is that when the form is submitted, the &lt;code&gt;postMail&lt;/code&gt; function gets called inside the event handler, which makes a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" rel="noopener noreferrer"&gt;&lt;code&gt;fetch&lt;/code&gt;&lt;/a&gt; call to &lt;code&gt;'/.netlify/functions/sendmail'&lt;/code&gt;. This path adheres to the following pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//[YOUR_URL]/.netlify/[FUNCTION_FOLDER]/[FUNCTION_NAME]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is of course going to trigger our function and, given that there is no error, send the data from the contact form to Sengrid, which in turn will process and send it to the email address defined in &lt;code&gt;SENDGRID_TO_EMAIL&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing your contact form
&lt;/h2&gt;

&lt;p&gt;Now you can test your form. Just run &lt;code&gt;netlify dev&lt;/code&gt; inside your project folder. This is going to start a server on &lt;code&gt;http://localhost:8888&lt;/code&gt;. If you then navigate to the page with your form, fill it out and submit, a mail should be sent to the email address you set in the &lt;code&gt;SENDGRID_TO_EMAIL&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;After you push your code and the build on Netlify is successful (if you have set up &lt;a href="https://docs.netlify.com/site-deploys/create-deploys/#deploy-with-git" rel="noopener noreferrer"&gt;continuous deployment in Netlify&lt;/a&gt;, the build will start automatically after pushing), the form should also work in production.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Cover image on top by &lt;a href="https://unsplash.com/@filisantillan?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Filiberto Santillán on Unsplash&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>gatsby</category>
      <category>serverless</category>
      <category>netlify</category>
    </item>
  </channel>
</rss>
