<?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: Austin Crim</title>
    <description>The latest articles on DEV Community by Austin Crim (@austincrim).</description>
    <link>https://dev.to/austincrim</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%2F298136%2Fdb3a21b3-ee07-4753-bf8f-de64ce51ef2c.jpeg</url>
      <title>DEV Community: Austin Crim</title>
      <link>https://dev.to/austincrim</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/austincrim"/>
    <language>en</language>
    <item>
      <title>JavaScript Dev Does Rust: Statements, expressions, and return values</title>
      <dc:creator>Austin Crim</dc:creator>
      <pubDate>Wed, 07 Jul 2021 03:03:28 +0000</pubDate>
      <link>https://dev.to/austincrim/javascript-dev-does-rust-statements-expressions-and-return-values-3e94</link>
      <guid>https://dev.to/austincrim/javascript-dev-does-rust-statements-expressions-and-return-values-3e94</guid>
      <description>&lt;p&gt;In Rust, a &lt;strong&gt;statement&lt;/strong&gt; is a piece of code that does not return a value and always ends with a semicolon&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"x is {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An &lt;strong&gt;expression&lt;/strong&gt; is code that evaluates to something. Most Rust code contains expressions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;y&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c"&gt;// 2 + 2 is an expression within a statement&lt;/span&gt;

&lt;span class="nf"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c"&gt;// do_something() is an expression the returns a value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This distinction is important, especially when reading functions. It might not be obvious what this function is returning at first glance. A function's return value can be the &lt;strong&gt;last expression evaluated&lt;/strong&gt; by body of the function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;sum_and_double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;summed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;summed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;  &lt;span class="c"&gt;// since this is the last expression, it is implicitly returned&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;summed * 2&lt;/code&gt; is the last expression so it evaluates and returns that value from the function. This would break if we added a semicolon because that would turn the line into a statement.&lt;/p&gt;

&lt;p&gt;This code would result in a compiler error for mismatched types because we are not returning an &lt;code&gt;i32&lt;/code&gt;, we are returning nothing!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;sum_and_double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;summed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;summed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c"&gt;// Compiler error! This is now a statement and nothing gets returned from the function!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can explicitly use the &lt;code&gt;return&lt;/code&gt; keyword in functions, which is required for returning early, but the implicit return is a de facto standard and you will see it everywhere.&lt;/p&gt;

&lt;p&gt;Pay attention to the semicolons!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Introducing Perusing the Platform: Discover the Native Capabilities of the Web</title>
      <dc:creator>Austin Crim</dc:creator>
      <pubDate>Thu, 17 Jun 2021 13:42:26 +0000</pubDate>
      <link>https://dev.to/austincrim/introducing-perusing-the-platform-discover-the-native-capabilities-of-the-web-1c1a</link>
      <guid>https://dev.to/austincrim/introducing-perusing-the-platform-discover-the-native-capabilities-of-the-web-1c1a</guid>
      <description>&lt;p&gt;I'm super excited to announce my latest project, &lt;a href="https://perusingtheplatform.com"&gt;Per&lt;strong&gt;using&lt;/strong&gt; the Platform!&lt;/a&gt; Join me through a series of demos and articles that will introduce the native JavaScript APIs that are built right into the browser.  &lt;/p&gt;

&lt;p&gt;The web as a platform is extremely powerful, not just because of its unparalleled reach, but also due to the decades of work that the language designers and browser vendors have put in to make it a robust runtime for our applications. You can do &lt;em&gt;so much&lt;/em&gt; with just JavaScript and a web browser and that's why I'm creating a resource to help developers discover and understand just how far they can go with vanilla JS.&lt;/p&gt;

&lt;p&gt;I just published the first article on PtP all about the Web Notifications API. I would love for you to check it out and feel free to provide me with any feedback!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>COBOL'in 🏀: What a 60-year-old language taught me about JavaScript</title>
      <dc:creator>Austin Crim</dc:creator>
      <pubDate>Wed, 02 Jun 2021 14:47:24 +0000</pubDate>
      <link>https://dev.to/austincrim/cobol-in-what-a-60-year-old-language-taught-me-about-javascript-87l</link>
      <guid>https://dev.to/austincrim/cobol-in-what-a-60-year-old-language-taught-me-about-javascript-87l</guid>
      <description>&lt;p&gt;Hey, I'm Austin, and I started my career a few years ago as a 20-year-old COBOL developer.  &lt;/p&gt;

&lt;p&gt;I can already hear the questions:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why would you subject yourself to that? Why not something relevant? What the heck is COBOL?  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;COmmon Business Oriented Language is a programming language that showed up in the late 1950s. It saw widespread adoption throughout many large companies and was usually employed for large-scale batch processing. Although it's over 60 years old, it is &lt;a href="https://www.zdnet.com/article/cobol-turns-60-why-it-will-outlive-us-all/"&gt;surprisingly common today&lt;/a&gt;. More recently, it got some &lt;a href="https://www.wired.com/story/cant-file-unemployment-dont-blame-cobol"&gt;time in the news&lt;/a&gt; when the governor of New Jersey made a public plea for COBOL developers to rescue the state unemployment system.  &lt;/p&gt;

&lt;p&gt;My COBOL story starts with my father who, after I finished high school, advised me to look into learning COBOL. He was a mainframe developer at a large university for almost the entirety of his career and with many of his contemporaries retiring, he knew that the amount of COBOL code still running would need maintainers with a specific set of skills (insert Liam Neeson gif). Unfortunately, I had to admit he was right. I landed a job as a mainframe engineer after just 18 months in school and started my career path in 2018 using technology from the 1950s.  &lt;/p&gt;

&lt;p&gt;I only spent a couple of years in that role before I transitioned to a team using a more modern stack and even though I now use things like React and Node every day, I have carried over some of the lessons I learned on the green screens.  &lt;/p&gt;

&lt;p&gt;Let's take a look at 3 ways that writing COBOL has made me a better web developer. &lt;/p&gt;

&lt;h2&gt;
  
  
  Requiring Readability 📚
&lt;/h2&gt;

&lt;p&gt;COBOL was designed to be readable by default. Its syntax is intentionally English-like in nature, with statements ending in periods and grouped by 'paragraphs'. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MOVE 5 TO NUM.
ADD 10 TO NUM.
PERFORM UNTIL NUM LESS THAN 10
  DISPLAY NUM
  SUBTRACT 1 FROM NUM
END PERFORM.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While admittedly verbose, it's also free of arcane symbols or abbreviations. Its verbosity is a side effect of its explicitness. Now, I'm not going to say that programming languages need to be designed this way in order to be readable, in fact, even COBOL can't &lt;em&gt;enforce&lt;/em&gt; readable code, it can only encourage it. But this general notion of readability as a first-class idea leads me to my first point: &lt;strong&gt;prioritizing readability pays off&lt;/strong&gt;.   &lt;/p&gt;

&lt;p&gt;We do a lot in the developer world in the name of readability. Everything from syntax highlighting and code formatters to abstractions like classes and functions improves our ability to quickly scan and reason about our code. So much time is spent in this realm because we have realized that &lt;strong&gt;readability leads to maintainability&lt;/strong&gt;. Code that's hard to read is hard to understand, if it's hard to understand, it's hard to fix bugs and add features.  &lt;/p&gt;

&lt;p&gt;Here are some quick hitters on how to improve the readability of your code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In general, avoid abbreviations when naming things. They oftn mk ur cod hrdr to read :).&lt;/li&gt;
&lt;li&gt;Make purity and immutability the default. Functions that reach outside their scope and variables that unexpectedly change are common sources of confusion in codebases. Do your best to avoid these techniques when practical. &lt;/li&gt;
&lt;li&gt;Keep functions small, without being dogmatic. It stands to reason that less code is easier to read than more code. Extracting another function costs very little, but can make a big difference in the long run. See more in the next section 👀.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One caveat that should go without saying, there are scenarios where you have to choose something like performance over readability, but when I write code I first ask myself "Is this readable?" before I try to optimize for anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Function Focused 🧐
&lt;/h2&gt;

&lt;p&gt;COBOL has no scope. If you declare a variable, it is for all intents and purposes, global, even if COBOL'ers wouldn't use that word. COBOL also doesn't have functions. It is &lt;em&gt;procedural&lt;/em&gt;, not functional or object-oriented (&lt;a href="https://www.ibm.com/docs/en/cobol-zos/4.2?topic=programs-writing-object-oriented"&gt;sorta&lt;/a&gt;).&lt;br&gt;&lt;br&gt;
A COBOL program is essentially a long list of instructions that get processed in a sequence. The way we organize these instructions in COBOL is with &lt;em&gt;paragraphs&lt;/em&gt;. A paragraph is a named grouping of instructions, 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;COMPUTE-TOTAL.
    MULTIPLY TAX-RATE BY SUBTOTAL GIVING TAX.
    ADD SUBTOTAL TO TAX GIVING TOTAL.
    SUBTRACT DISCOUNT FROM TOTAL.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our paragraph defined, we can then execute it whenever we want with the &lt;code&gt;PERFORM&lt;/code&gt; keyword.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PERFORM COMPUTE-TOTAL.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since COBOL has no scope and no functions, it quickly becomes apparent that the frequent use of paragraphs is imperative to maintaining a halfway-decent codebase. Many teams even develop style guides with rules like:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All code must be in a paragraph&lt;/li&gt;
&lt;li&gt;Paragraphs must be named clearly&lt;/li&gt;
&lt;li&gt;Paragraphs should have one primary responsibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If these ideas around paragraphs sound familiar it's because many JavaScript developers talk similarly about &lt;em&gt;functions&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;Functional programming in JavaScript has become somewhat in vogue as of late and for good reason! If you're like me, you might have thought you hated programming when you were in Java class and got yet another &lt;code&gt;NullPointerException&lt;/code&gt; trying to write a tip calculator. But pure functions offer a much clearer mental model: dump values in, get values out, consistently.&lt;br&gt;&lt;br&gt;
Small, pure functions are the easiest to test, read, and maintain, so why not try to build your whole codebase out of such functions? Even COBOL, without the first-class notion of a function, understood code that can be grouped and reused is paramount to building applications for the long haul. &lt;/p&gt;

&lt;h2&gt;
  
  
  Talking Testing 🧪
&lt;/h2&gt;

&lt;p&gt;Up to this point, my comments on COBOL have been mostly positive, but that's about to change. The biggest hurdle in my time as a mainframe dev was &lt;em&gt;testing my code&lt;/em&gt;. By their very nature, most COBOL codebases are supporting old, long-running processes and applications. They are often products of many different developers making changes over decades and, due to the lack of tooling, the resulting code is not easy to test. Impact analysis and unit testing were by far the most time-consuming tasks in any feature request or bugfix. There is rarely a path forward on how to execute your program under certain conditions or identifying what parts of the codebase your change might negatively affect.  &lt;/p&gt;

&lt;p&gt;Again, I mainly attribute this to the lack of sophisticated tooling and it brings me to my final point, &lt;em&gt;automated testing in JavaScript is a gift&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;To the chagrin of some, the JavaScript ecosystem has an embarrassment of riches when it comes to choice. There is an NPM package for checking if a number is even, for goodness sakes. Search NPM for "testing" and you get back 14,534 results. The point is you can write tests in just about any way imaginable; the barrier to entry has never been lower. Having an automated test suite in place skyrockets developers' confidence, encourages frequent refactors, and can singlehandedly change the future of a given application.&lt;br&gt;&lt;br&gt;
There are umpteen resources out there telling you why testing is important, so I will stop preaching here, but I will offer up a couple thoughts on getting started.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Focus on the highest value, lowest friction tests first. End-to-end web tests using something like Cypress is a great way to ensure the main functionality of your app is working before you get to production.&lt;/li&gt;
&lt;li&gt;Run tests automatically and frequently. Whether in continuous integration or a git hook, make sure your feedback loop is short and you get informed of test failures at the right times.&lt;/li&gt;
&lt;li&gt;Kent C. Dodds puts it best: "The more your tests resemble the way your software is used, the more confidence they can give you."&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Closing Comments 🚪
&lt;/h2&gt;

&lt;p&gt;When COBOL was released in the 1950s, programmers wanted to write resilient applications that solved problems and while our tools have changed dramatically, I would argue our goals mostly remain the same. Frameworks and languages come and go at a breakneck speed, but if we can glean principles from those who came before us, our knowledge will stand the erosion of time, not unlike a lot of COBOL code still running today.  &lt;/p&gt;

&lt;p&gt;Thanks for your time.&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>AWS CDK with Go: Hello World</title>
      <dc:creator>Austin Crim</dc:creator>
      <pubDate>Tue, 11 May 2021 22:02:28 +0000</pubDate>
      <link>https://dev.to/austincrim/aws-cdk-with-go-hello-world-2119</link>
      <guid>https://dev.to/austincrim/aws-cdk-with-go-hello-world-2119</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I recently started exploring the AWS CDK using Go. The Go CDK library is currently in Developer Preview, meaning the APIs are subject to change and it should not be used in production. However, it should be used to experiment and provide feedback to AWS!&lt;br&gt;&lt;br&gt;
I wanted to spin up a simple Lambda fronted by API Gateway to create an HTTP API, a very common use case. I have pasted the full source of both the CDK and the Lambda handler below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// lib/cdk.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/aws/aws-cdk-go/awscdk"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/aws-cdk-go/awscdk/awsapigatewayv2"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/aws-cdk-go/awscdk/awsapigatewayv2integrations"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/aws-cdk-go/awscdk/awslambda"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/constructs-go/constructs/v3"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/jsii-runtime-go"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;GoCdkStackProps&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;awscdk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StackProps&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewGoCdkStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="n"&gt;constructs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;GoCdkStackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;awscdk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sprops&lt;/span&gt; &lt;span class="n"&gt;awscdk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StackProps&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;sprops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StackProps&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;awscdk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sprops&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// The code that defines your stack goes here&lt;/span&gt;

    &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;awslambda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gofunction"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;awslambda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FunctionProps&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;FunctionName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hellogo"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;         &lt;span class="n"&gt;awslambda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AssetCode_FromAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../handler"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"handler"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Runtime&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;awslambda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Runtime_GO_1_X&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;integration&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;awsapigatewayv2integrations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewLambdaProxyIntegration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;awsapigatewayv2integrations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LambdaProxyIntegrationProps&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;              &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;PayloadFormatVersion&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;awsapigatewayv2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PayloadFormatVersion_VERSION_1_0&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;awsapigatewayv2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHttpApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"goapi"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;awsapigatewayv2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpApiProps&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ApiName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hellogoapi"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRoutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;awsapigatewayv2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRoutesOptions&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;        &lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Integration&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;integration&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="n"&gt;stack&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;awscdk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;NewGoCdkStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"GoCdkStack"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;GoCdkStackProps&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;awscdk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;StackName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GoCDKStack"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;env&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="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Synth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// env determines the AWS environment (account+region) in which our stack is to&lt;/span&gt;
&lt;span class="c"&gt;// be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;awscdk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;awscdk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CDK_DEFAULT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="n"&gt;Region&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CDK_DEFAULT_REGION"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// handler/main.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/aws/aws-lambda-go/events"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/aws-lambda-go/lambda"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;HandleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;APIGatewayProxyRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;APIGatewayProxyResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryStringParameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Friend"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;APIGatewayProxyResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, %s!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lambda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HandleRequest&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;Allow me to highlight a few concepts that tripped me up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding the Go CDK packages
&lt;/h3&gt;

&lt;p&gt;Since the CDK bindings for Go are currently in developer preview, the documentation is not quite as fleshed out as the other supported languages. This made getting started a little hairy. In the end I found most of what I needed &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-construct-library.html"&gt;here&lt;/a&gt;, after selecting the v2 release candidate from the menu in the top right.&lt;br&gt;&lt;br&gt;
One major benefit of CDK 2.0 is having all the various packages under a single namespace. This makes it trivial to grab more dependencies as you go, simply changing the last node of your import statements.  &lt;/p&gt;

&lt;h3&gt;
  
  
  jsii.String()?
&lt;/h3&gt;

&lt;p&gt;Most examples of Go CDK that I found on AWS' docs included calls to &lt;code&gt;jsii.String()&lt;/code&gt; or similar. This call has to wrap any literal data types that you wish to pass, such as string or integer primitives. All construct options structs take pointers, even for things like strings or integers. This is because Go does not natively support optional struct fields. &lt;code&gt;jsii.String()&lt;/code&gt; will automatically provide a pointer to your string literal value, this allows for a &lt;code&gt;nil&lt;/code&gt; pointer to be used for optional fields that you choose not to provide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Specifying a Lambda Handler
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;awslambda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gofunction"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;awslambda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FunctionProps&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;jsii&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"handler"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&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 option took me the longest to figure out and partially inspired me to write this post. When specifying the &lt;code&gt;Handler&lt;/code&gt; option of a new Lambda function, you specify the &lt;strong&gt;name of the executable file generated by &lt;code&gt;go build&lt;/code&gt;&lt;/strong&gt;. So in my scenario, I have a folder named &lt;strong&gt;handler&lt;/strong&gt; that contains a &lt;strong&gt;main.go&lt;/strong&gt; file. When built, this creates a &lt;strong&gt;handler&lt;/strong&gt; executable. This is what needs to go in the &lt;code&gt;Handler&lt;/code&gt; struct field.&lt;br&gt;&lt;br&gt;
Another important note, when building your executable, &lt;strong&gt;you have to run &lt;code&gt;GOOS=linux go build&lt;/code&gt;&lt;/strong&gt; or the Windows equivalent. This tells the Go cli to build an executable for the Linux OS which is where your Lambda will actually run. If you don't do this, you will get a runtime error when executing your lambda.  &lt;/p&gt;

&lt;p&gt;That wraps it up for this post, let me know if you run into any other common issues I could add!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>go</category>
    </item>
    <item>
      <title>How I Added Themes to My Website Using Tailwind</title>
      <dc:creator>Austin Crim</dc:creator>
      <pubDate>Thu, 08 Apr 2021 19:17:27 +0000</pubDate>
      <link>https://dev.to/austincrim/how-i-added-themes-to-my-website-using-tailwind-3ig3</link>
      <guid>https://dev.to/austincrim/how-i-added-themes-to-my-website-using-tailwind-3ig3</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I recently added theming to my &lt;a href="https://austincrim.com"&gt;website&lt;/a&gt; and I wanted to quickly jot down my implementation. I ran into a little friction along the way, but I am really happy with how the result looks and feels. I'm excited about adding even more themes!&lt;br&gt;&lt;br&gt;
A lot of this is based on Tailwind Labs' own &lt;a href="https://www.youtube.com/watch?v=MAtaT8BZEAo"&gt;theming video&lt;/a&gt; and I highly encourage you to start there if you are interested in adding themes with Tailwind. All code examples will assume that your project is already integrated with TailwindCSS.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note ⚠️: Most of this article applies to any site, regardless if you use TailwindCSS. If you're not using Tailwind, feel free to read on, you might learn something!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;The modern mechanism for theming on the web today is through CSS Custom Properties (aka CSS Variables). They are incredibly flexible and make theming much simpler than it used to be. A basic workflow for adding theme support to a website looks something like this:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;define color palettes in CSS variables&lt;/li&gt;
&lt;li&gt;use CSS variables wherever a theme-specific value is needed&lt;/li&gt;
&lt;li&gt;add/remove theme class names in the DOM based on some action (button click, dropdown select, etc.)&lt;/li&gt;
&lt;li&gt;optionally persist a user's preference&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Tailwind, an extra step is required somewhere in that list: &lt;strong&gt;generating new class names with your &lt;code&gt;tailwind.config.js&lt;/code&gt;&lt;/strong&gt;. Therein lies the rub that makes theming with Tailwind different. I found this process to offer some friction, but being a major TW lover, I persevered in the name of not writing custom CSS classes by hand.&lt;/p&gt;
&lt;h2&gt;
  
  
  Defining Your Palette in CSS Variables
&lt;/h2&gt;

&lt;p&gt;This step honestly contained the bulk of the time spent in my case. I was trying to craft each theme from scratch, so coming up with all of the color values took a decent amount of trial and error.   &lt;/p&gt;

&lt;p&gt;Using the &lt;a href="https://tailwindcss.com/docs/customizing-colors#color-palette-reference"&gt;full TailwindCSS color palette&lt;/a&gt; as a reference, I copied and pasted RGB values into my CSS variables to preview them on my site. Not the best workflow, but I stuck with it and got a good result. I wanted to stay within Tailwind colors, but unfortunately, I don't know of a way to reference Tailwind colors in a plain CSS file. This resulted in my copy/paste workflow which, in my opinion, was the most painful part of the whole theming process.  &lt;/p&gt;

&lt;p&gt;After finishing a theme, my CSS would look something 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="nc"&gt;.theme-dark&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--color-base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;39&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                &lt;span class="c"&gt;/* gray-900 */&lt;/span&gt;
    &lt;span class="py"&gt;--color-text-base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;243&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;244&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;246&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c"&gt;/* gray-100 */&lt;/span&gt;
    &lt;span class="py"&gt;--color-off-base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;            &lt;span class="c"&gt;/* gray-800 */&lt;/span&gt;
    &lt;span class="py"&gt;--color-text-muted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;229&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;231&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;235&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c"&gt;/* gray-200 */&lt;/span&gt;
    &lt;span class="py"&gt;--color-muted-offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;209&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;213&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;219&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c"&gt;/* gray-300 */&lt;/span&gt;
    &lt;span class="py"&gt;--color-primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;147&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;197&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;253&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c"&gt;/* blue-300 */&lt;/span&gt;
    &lt;span class="py"&gt;--color-secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;96&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;165&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;250&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c"&gt;/* blue-400 */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, I attempted to name my variables generically enough to be reusable while maintaining clarity. I have a few base colors for backgrounds and text, as well as offsets, a primary, and a secondary. You can include as many different variables as your theme requires, but I tried to keep it reasonably simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating and Using New Theme Classes
&lt;/h2&gt;

&lt;p&gt;Once you have your themes outlined in CSS variables, you've done the hard bit. Now we are almost to the fun part! To use these dynamic theme colors in Tailwind, you have to generate utility classes using the config file. If you have never tweaked a &lt;code&gt;tailwind.config.js&lt;/code&gt; file, this step might take some getting used to, but it is fairly straightforward once you have had some practice.  &lt;/p&gt;

&lt;p&gt;Here's a snippet from my config file:&lt;br&gt;&lt;br&gt;
(For an explanation on the &lt;code&gt;withOpacity&lt;/code&gt; function, please refer to the Tailwind Labs video linked above.)&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="nx"&gt;withOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;variableName&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="nx"&gt;opacityValue&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;opacityValue&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="s2"&gt;`rgba(var(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;variableName&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;opacityValue&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="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`rgb(var(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;variableName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;))`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&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="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// we want to extend the current colors instead of replacing them&lt;/span&gt;
        &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// this will generate utilities like `bg-base` and `bg-primary`&lt;/span&gt;
            &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;withOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--color-base&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;off-base&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;withOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--color-off-base&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;withOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--color-primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;withOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--color-secondary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;muted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;withOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--color-text-muted&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="c1"&gt;// these classes end up like `text-base` and `text-primary`&lt;/span&gt;
            &lt;span class="na"&gt;textColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;withOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--color-text-base&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;muted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;withOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--color-text-muted&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;muted-offset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;withOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--color-muted-offset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;withOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--color-primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;withOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--color-secondary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since our utility classes reference CSS variables, their values will respond when we toggle our theme classes. In my example, I only generated utilities for &lt;code&gt;backgroundColor&lt;/code&gt; and &lt;code&gt;textColor&lt;/code&gt; specifically. You can generate classes for any applicable properties or generate classes for all color properties using the &lt;code&gt;theme.extend.colors&lt;/code&gt; key in the config.&lt;br&gt;&lt;br&gt;
Now using these classes is as simple as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;'theme-dark bg-base text-primary'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Hello Tailwind Themes!
&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's also important to apply a theme class by default to ensure correct styling on the initial page load. You can also define your base theme on the CSS &lt;code&gt;:root&lt;/code&gt; selector and those values will take effect by default, without adding any extra classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Switching Themes on the Fly
&lt;/h2&gt;

&lt;p&gt;Now that we have our classes generated and applied, we can start switching themes! This process just consists of toggling different class names on the document. On my website, I show a list of the different available themes and, when one is clicked, I run something like this:&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentTheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newTheme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, I am replacing the current theme class with whatever the user has selected. I'm doing it on the &lt;code&gt;documentElement&lt;/code&gt; but you can apply this to wherever you want your top-level theme class to live.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note ⚠️: My website uses React, so I track the &lt;code&gt;currentTheme&lt;/code&gt; in a piece of state. However, this can be done in several ways in vanilla JavaScript, like a global variable or a &lt;code&gt;data-theme&lt;/code&gt; attribute. The important part is that you swap out the current theme for the user's selection.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Hanging on to a User's Choice
&lt;/h2&gt;

&lt;p&gt;If you've made it this far, congrats! You now have fully functioning themes on your site. But you might notice if you select a theme and refresh the page, you've lost your choice! This is where data persistence comes into play. Don't worry, it can be really simple! Here's a look at how my site does 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="nx"&gt;pickTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newTheme&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;newTheme&lt;/span&gt; &lt;span class="o"&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&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;newTheme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crimTheme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newTheme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;setCurrent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newTheme&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 &lt;code&gt;pickTheme&lt;/code&gt; function is called when a theme choice is selected.&lt;br&gt;&lt;br&gt;
Let's break it down:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;return early if they selected the theme that's currently applied to prevent unnecessary work&lt;/li&gt;
&lt;li&gt;replace the current theme class with the new one&lt;/li&gt;
&lt;li&gt;save the user's choice in browser local storage&lt;/li&gt;
&lt;li&gt;update my current theme state (React style)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a great start! Now when a user selects a new theme, we get it applied to the DOM and then save it to the browser's local storage.&lt;br&gt;&lt;br&gt;
There is one more step we have to do before the whole experience works smoothly. Currently, even though our theme choice is in local storage, if we refresh the page we don't see any difference. On page load, we need to check local storage and get the theme applied right away, before the user sees the default theme. Here's what I did:&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;// theme.js&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;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crimTheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crimTheme&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;theme-light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crimTheme&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;theme-light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not too bad! We first check local storage for our theme and apply it if it exists. If not, we set them up with the default theme. I load this &lt;code&gt;theme.js&lt;/code&gt; file directly in my &lt;code&gt;index.html&lt;/code&gt; to ensure it runs early enough to prevent flashes.&lt;/p&gt;

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

&lt;p&gt;Big kudos to you if you made it this far. We have accomplished a lot!&lt;br&gt;&lt;br&gt;
Let's review:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We set up our themes with CSS variables&lt;/li&gt;
&lt;li&gt;We generated custom Tailwind classes to apply our CSS variable values&lt;/li&gt;
&lt;li&gt;We allowed users to swap themes by updating our theme class in the DOM&lt;/li&gt;
&lt;li&gt;Finally, we boosted the user experience by saving and retrieving a user's theme preference in local storage&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Theming adds a lot of personality to sites and I hope to see more of it in the future. Reach out and show me your themed sites!&lt;/p&gt;

</description>
      <category>css</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Svelte Pomodoro Timer</title>
      <dc:creator>Austin Crim</dc:creator>
      <pubDate>Mon, 06 Jul 2020 23:37:20 +0000</pubDate>
      <link>https://dev.to/austincrim/svelte-pomodoro-timer-2fhn</link>
      <guid>https://dev.to/austincrim/svelte-pomodoro-timer-2fhn</guid>
      <description>&lt;p&gt;I have been wanting to beef up my Svelte skills and what better way than a quick project! I just finished up a simple &lt;a href="https://en.wikipedia.org/wiki/Pomodoro_Technique"&gt;Pomodoro Timer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check out the app &lt;a href="https://svelte-pomodoro.vercel.app/"&gt;here&lt;/a&gt; and the source &lt;a href="https://github.com/austincrim/timer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let me know what you think!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Quick CSS Transition Explainer</title>
      <dc:creator>Austin Crim</dc:creator>
      <pubDate>Tue, 30 Jun 2020 19:34:59 +0000</pubDate>
      <link>https://dev.to/austincrim/quick-css-transition-explainer-3kn0</link>
      <guid>https://dev.to/austincrim/quick-css-transition-explainer-3kn0</guid>
      <description>&lt;p&gt;CSS transitions are easy to use and really add that final touch of polish to a UI. I love transitions and they make a site look more professional when used correctly. They were a little confusing at first for me, so I decided to whip up a quick CodePen showing how transitions are written.&lt;/p&gt;

&lt;p&gt;Transitions are used to smoothly transition from one style to another. Here's an example using a button with hover and active states.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/austincrim/embed/rNxYMxa?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>css</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Recreating the macOS Mail UI</title>
      <dc:creator>Austin Crim</dc:creator>
      <pubDate>Tue, 23 Jun 2020 21:54:55 +0000</pubDate>
      <link>https://dev.to/austincrim/recreating-the-macos-mail-ui-4hok</link>
      <guid>https://dev.to/austincrim/recreating-the-macos-mail-ui-4hok</guid>
      <description>&lt;p&gt;After seeing the design of the newly announced macOS, Big Sur, I decided to try to remake the user interface of the macOS Mail app. I used TailwindCSS and Heroicons by Steve Schoeger to help me along.&lt;/p&gt;

&lt;p&gt;Check it out &lt;a href="https://big-sur-mail.vercel.app"&gt;here&lt;/a&gt; (not mobile friendly) and look at the source &lt;a href="https://github.com/austincrim/quick-design-projects/tree/master/big-sur-mail"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let me know what you think!&lt;/p&gt;

</description>
      <category>html</category>
      <category>css</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Rebuilding My Personal Site with Next.js and TailwindCSS</title>
      <dc:creator>Austin Crim</dc:creator>
      <pubDate>Tue, 26 May 2020 19:00:51 +0000</pubDate>
      <link>https://dev.to/austincrim/rebuilding-my-personal-site-with-next-js-and-tailwindcss-47k6</link>
      <guid>https://dev.to/austincrim/rebuilding-my-personal-site-with-next-js-and-tailwindcss-47k6</guid>
      <description>&lt;h1&gt;
  
  
  Background
&lt;/h1&gt;

&lt;p&gt;After publishing the first iteration of my personal website around a year ago, I grew tired of the design and wanted to explore the new technologies I had been learning. My old site was written in plain HTML and CSS using the Bootstrap 4 framework. This was a great exercise at the time and it taught me some important lessons about CSS and design in general, but it was time for change. &lt;/p&gt;

&lt;p&gt;Here is what my old site looked like: &lt;a href="https://austincrim.me"&gt;Old Website&lt;/a&gt;.&lt;br&gt;
And this is the new and improved version: &lt;a href="https://portfolio.austcrim.now.sh"&gt;New Website&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  The New Stack
&lt;/h1&gt;

&lt;p&gt;My new portfolio site is built using &lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt; and &lt;a href="https://tailwindcss.com/"&gt;TailwindCSS&lt;/a&gt;. I love both of these technologies and their developer experience is top notch. I definitely recommend checking out these frameworks if you're interested in React or CSS. &lt;/p&gt;
&lt;h3&gt;
  
  
  Using Next.js
&lt;/h3&gt;

&lt;p&gt;Currently, my portfolio site is a single page, statically generated by Next. It reads in data at build time to create the HTML, allowing the server to respond with static HTML for fast rendering. Here's how easy it is to get data at build time:&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;// index.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStaticProps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;skills&lt;/span&gt; &lt;span class="p"&gt;}&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="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data/skills.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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;projects&lt;/span&gt; &lt;span class="p"&gt;}&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="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data/projects.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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;skills&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;projects&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;I can then access this data in my homepage like this:&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;// index.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;skills&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;projects&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="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;skills&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SkillCard&lt;/span&gt;
                &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imagePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case, I'm reading files to get my data, but you could do any kind of data fetching here: API calls, database queries, you name it. You can read more about SSG (static site generation) &lt;a href="https://nextjs.org/blog/next-9-3#next-gen-static-site-generation-ssg-support"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Tailwind
&lt;/h3&gt;

&lt;p&gt;I have been an huge fan of Tailwind ever since I discovered it. I find the utility-first workflow helps me move faster as a developer and the built-in classes allow me to produce more consistent, intentional designs. I was wary of Tailwind when I first read about it and it does come with trade-offs, but I was hooked after the first time I actually used it to build something. I would encourage anyone interested in Tailwind to give it a try before forming strong opinions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Future Plans
&lt;/h3&gt;

&lt;p&gt;While I am happy with how my new design turned out, I have some future additions I wish to make. I want to further my knowledge of Next.js by adding a blog, complete with a built-in Markdown editor for posts. I also need to transition the new website to my preferred domain: austincrim.me. The last thing on my backlog is a fan-favorite: dark mode.&lt;/p&gt;

&lt;p&gt;The source for my portfolio site can be found &lt;a href="https://github.com/austincrim/next-personal-site"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading and feel free to offer feedback or comments!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>css</category>
    </item>
    <item>
      <title>Cooking in quarantine? Check out this Twilio recipe finder!</title>
      <dc:creator>Austin Crim</dc:creator>
      <pubDate>Wed, 08 Apr 2020 18:49:58 +0000</pubDate>
      <link>https://dev.to/austincrim/cooking-in-quarantine-check-out-this-twilio-recipe-finder-4ape</link>
      <guid>https://dev.to/austincrim/cooking-in-quarantine-check-out-this-twilio-recipe-finder-4ape</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;With a growing populace "sheltering in place" and restaurants closing their doors temporarily, the need for home cooking is on the rise and if you're anything like me, you are lacking inspiration. That is why I decided to help myself out with a recipe finder! Simply send a text to +1 (202) 952-8194 with a comma separated list of ingredients and receive delicious recipes. If only Twilio could cook the meals too...&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%2F34t0qs77uktqufvlt9uh.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%2F34t0qs77uktqufvlt9uh.PNG" alt="Example Interaction"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also send a number as the last parameter to specify how many recipes to bring back (e.g. Carrots, potatoes, 7). &lt;strong&gt;Keep in mind&lt;/strong&gt;, each recipe will be a separate text message and contain an image.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I built it
&lt;/h2&gt;

&lt;p&gt;I wrote the project in NodeJS and it is currently hosted on Heroku. I utilized Twilio's programmable SMS API as well as the &lt;a href="https://spoonacular.com/food-api" rel="noopener noreferrer"&gt;Spoonacular recipe API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/austincrim/dev-to-twilio" rel="noopener noreferrer"&gt;Here's the source code.&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
FYI, I'm currently working through an issue where Twilio is slow to post my message to my app. This causes intermittent delays in the recipe response. Thanks for understanding!&lt;/p&gt;

&lt;p&gt;Let me know what you think in the comments!&lt;/p&gt;

</description>
      <category>twiliohackathon</category>
      <category>showdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
