<?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>Forem: Abhijit Hota</title>
    <description>The latest articles on Forem by Abhijit Hota (@kretaceous).</description>
    <link>https://forem.com/kretaceous</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%2F314261%2F628ae9e8-8c9b-4486-bc46-cc6167c83767.jpeg</url>
      <title>Forem: Abhijit Hota</title>
      <link>https://forem.com/kretaceous</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kretaceous"/>
    <language>en</language>
    <item>
      <title>Poor man's CI/CD with GitHub Webhooks</title>
      <dc:creator>Abhijit Hota</dc:creator>
      <pubDate>Wed, 05 Oct 2022 05:02:17 +0000</pubDate>
      <link>https://forem.com/kretaceous/poor-mans-cicd-with-github-webhooks-akf</link>
      <guid>https://forem.com/kretaceous/poor-mans-cicd-with-github-webhooks-akf</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;In my 5th semester of college (mid 2021), I was in-charge of the Web Operations team at &lt;a href="https://ecell.iitm.ac.in/home" rel="noopener noreferrer"&gt;E-Cell IITM&lt;/a&gt;. Our responsibility was to make web applications for events, workshops and competitions. The tech stack was primarily Node.js with Express, React and MongoDB for the database. If you're a &lt;em&gt;full-stack developer&lt;/em&gt;, you might know this as the MERN stack. &lt;/p&gt;

&lt;p&gt;The environment was fast-paced. We were building a lot of things and breaking more of them in the process. It was like a startup. The highest number of users for an application was only 6.5k. And that's the reason we could experiment a lot of stuff. Following best practices was something we tried a lot to inculcate by adding tools like linters, formatters, pre-commit hooks, etc. but again, &lt;strong&gt;we were all freshers; making and breaking things&lt;/strong&gt; and somewhere down the line we would just push something with just a commit message of &lt;code&gt;fix stuff&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We have an in-premise server in the institute cluster for hosting the MERN applications. It is just an Ubuntu box with &lt;a href="https://pm2.io/" rel="noopener noreferrer"&gt;&lt;code&gt;pm2&lt;/code&gt;&lt;/a&gt; installed for running Node.js apps. A lot of our time was spent in deploying very, &lt;em&gt;very&lt;/em&gt; minor changes. Fix-a-typo-in-a-static-page-level minor. The process was generally this: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect to institute's VPN if you're not in Insti's network&lt;/li&gt;
&lt;li&gt;SSH into the server&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git pull&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run build&lt;/code&gt; if it's a React application&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pm2 restart frontend-server&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Easy and simple. Manual and boring. Perfect characteristics of something that needs to be automated. Automation is the mother of invention when it comes to software development and so I went looking for answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-hosted GitHub Actions
&lt;/h2&gt;

&lt;p&gt;The first and the most obvious solution was to use &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;. I've never used them before and was pretty excited to learn and use it. My excitement was soon doubled when I got to know that you can &lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners" rel="noopener noreferrer"&gt;self-host them&lt;/a&gt;. I was able to learn it and setup it for our backend Node.js monolith in a day. But something felt off.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It required installing a lot of stuff to a rather humble machine. It also demanded a lot of memory relative to what our applications were using. To give you an idea, our main backend service uses &lt;strong&gt;105 MB&lt;/strong&gt; at maximum whereas the runner used around &lt;strong&gt;1 GB&lt;/strong&gt; in average.&lt;/li&gt;
&lt;li&gt;The action was such that it checked out the whole repository every time. The repository was, in a way, large.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;All our applications stayed in the home directory (&lt;code&gt;$HOME&lt;/code&gt;). I could not figure out how to checkout the repository in the same place where it was and got around it by adding &lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners/running-scripts-before-or-after-a-job" rel="noopener noreferrer"&gt;post-job scripts&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;We weren't looking at a lot of scale so this level of sophistication felt overkill.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All we wanted to do was to run a few scripts on a &lt;code&gt;git push&lt;/code&gt;. Surely, there was a minimal way of doing this? &lt;/p&gt;

&lt;h2&gt;
  
  
  The hack which seemed like the solution
&lt;/h2&gt;

&lt;p&gt;Webhooks are an elegant way to communicate from server to client. They are one of the simpler ways to implement &lt;em&gt;event-driven architecture&lt;/em&gt;. Think of webhooks as a third-party server sending an HTTP POST request to your own server. This doesn't require you to &lt;a href="https://en.wikipedia.org/wiki/Polling_(computer_science)" rel="noopener noreferrer"&gt;keep asking that server for data&lt;/a&gt; or keep an open connection. GitHub offers &lt;a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/about-webhooks" rel="noopener noreferrer"&gt;Webhooks&lt;/a&gt; for a lot of repository and organisation level events. &lt;/p&gt;

&lt;p&gt;Here's how they work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You provide a URL and a secret to GitHub. GitHub stores the hash of that secret.&lt;/li&gt;
&lt;li&gt;You choose the events you want a webhook for.&lt;/li&gt;
&lt;li&gt;Whenever that event happens, GitHub sends a &lt;code&gt;JSON&lt;/code&gt; or &lt;code&gt;XML&lt;/code&gt; payload via a &lt;code&gt;HTTP POST&lt;/code&gt; request to the URL you provided in step 1. It also sends the signature which is derived from the secret you provided. &lt;/li&gt;
&lt;li&gt;In your server, you check the signature with your original signature. If it's correct, you handle the payload however you want to.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The payload being talked about contains a &lt;a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads" rel="noopener noreferrer"&gt;lot of information related to the event&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;And there was it. A simple &lt;code&gt;HTTP POST&lt;/code&gt; containing relevant data. The idea was to commit and push with a commit message starting with &lt;code&gt;deploy&lt;/code&gt;. The commit message, committer, files changed, etc. would be included in the &lt;a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#push" rel="noopener noreferrer"&gt;payload for the push event&lt;/a&gt;. And here's how it panned out in our case:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Provide a URL like &lt;code&gt;https://ecell.iitm.ac.in/api/gh-webhook&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Choose to send the webhook only on &lt;code&gt;push&lt;/code&gt; events. &lt;/li&gt;
&lt;li&gt;When we receive a webhook, check if the commit message starts with &lt;code&gt;deploy&lt;/code&gt;, the committer is one of the admins and some code is changed.&lt;/li&gt;
&lt;li&gt;Run a simple script:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git pull
   npm run build
   pm2 restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step by step instructions
&lt;/h2&gt;

&lt;p&gt;Let's try to replicate this with an example repository and &lt;code&gt;localhost&lt;/code&gt; as the server. Find the repository here: &lt;a href="https://github.com/abhijit-hota/webhook-example" rel="noopener noreferrer"&gt;&lt;code&gt;webhook-example&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the webhook to the repository
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Choose a repository you want to work on. You can fork the example repository. Make sure to rename &lt;code&gt;.template.env&lt;/code&gt; to &lt;code&gt;.env&lt;/code&gt; and change the secret string if you want to.&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;Settings&lt;/code&gt; &amp;gt; &lt;code&gt;Webhooks&lt;/code&gt; &amp;gt; &lt;code&gt;Add webhook&lt;/code&gt;. Or just visit &lt;code&gt;https://github.com/&amp;lt;username&amp;gt;/&amp;lt;repo-name&amp;gt;/settings/hooks/new&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We will start the server and expose it via a tunnel. I'm using &lt;a href="https://github.com/cloudflare/cloudflared" rel="noopener noreferrer"&gt;&lt;code&gt;cloudflared&lt;/code&gt;&lt;/a&gt; but you can use anything else if you want to. &lt;/li&gt;
&lt;li&gt;As you can see, we have chosen &lt;code&gt;application/json&lt;/code&gt; as the content type cause we want the payload in JSON. For the secret, you can put any random string but make sure you remember/note what you put there. For the example repository you also have to update your &lt;code&gt;.env&lt;/code&gt; file. Details in the next section.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/2022-10-05-21-59-23.png"&gt;
&amp;gt; &lt;strong&gt;Note about SSL&lt;/strong&gt;: We've only disabled it because it's just a demo. Enable this without fail in your real applications.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Listening to the webhook in your server
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;a href="https://github.com/abhijit-hota/webhook-example/blob/master/index.js" rel="noopener noreferrer"&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/a&gt; is the entry point for our server. It's a simple static site server in Node.js which serves a React build. We mount the webhook &lt;em&gt;listener&lt;/em&gt; in the &lt;code&gt;/webhook&lt;/code&gt; route. Notice how we used this route in the URL we provided to GitHub in the previous step.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="c1"&gt;// Mount the webhook listener&lt;/span&gt;
   &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/webhook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;webhookRouter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;In &lt;a href="https://github.com/abhijit-hota/webhook-example/blob/master/webhook.js" rel="noopener noreferrer"&gt;&lt;code&gt;webhook.js&lt;/code&gt;&lt;/a&gt;, we first parse the &lt;code&gt;.env&lt;/code&gt; file which contains our secret.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;dotenv&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SECRET&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;GH_WEBHOOK_SECRET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Next we add 2 middlewares. The first middleware stores the raw request buffer. We do this because parsing damages the integrity of the signature.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buf&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;ol&gt;
&lt;li&gt;The second middleware verifies the signature sent with our secret that only we and GitHub knows. This way we know the request is actually a valid one from GitHub. This is why SSL is so important because without that you're exposing this request to &lt;a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack" rel="noopener noreferrer"&gt;MITM attacks&lt;/a&gt;.
&lt;/li&gt;
&lt;/ol&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ghSign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-hub-signature-256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ourSign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SECRET&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&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="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ghSign&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;ourSign&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&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;ol&gt;
&lt;li&gt;And finally, we listen to it in the &lt;code&gt;POST&lt;/code&gt; handler.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;webhookRouter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, if you push some changes, you can see the payload in your terminal where the server is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"refs/heads/master"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"repository"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"webhook-example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"full_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abhijit-hota/webhook-example"&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"pusher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abhijit-hota"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abhihota025@gmail.com"&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"head_commit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6c386ca6d6f3df80ea7b0abd59c3b9a8c3983726"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chore: add comments and increase legibility"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-10-05T22:19:21+05:30"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abhijit-hota"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abhihota025@gmail.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abhijit-hota"&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"added"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"removed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"modified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="s2"&gt;".template.env"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="s2"&gt;"webhook.js"&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've removed &lt;em&gt;a lot&lt;/em&gt; of stuff from the payload and have just shown the relevant ones. Now all that left is to run commands based on the data we get. More on this in the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building and executing commands
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;We're only going to see how to solve it for Linux but it shouldn't be that hard to build queries for Windows systems in a similar way, if you're using Windows at all for deployments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;We check for the commit message and the pusher. You can of course, choose your own logic here:
&lt;/li&gt;
&lt;/ol&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="na"&gt;head_commit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pusher&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&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="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;commit&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="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deploy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;pusher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;abhijit-hota&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="nx"&gt;res&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Deployment skipped.&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;ol&gt;
&lt;li&gt;We create an array of commands to run. And we add to it as we go over the changes. The code is pretty self-explanatory and I've added comments too.
&lt;/li&gt;
&lt;/ol&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;commands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cd &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;changes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modified&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;added&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removed&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;requiresReinstall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;change&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;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requiresReinstall&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;commands&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;npm install&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;hasFrontendChanges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;change&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;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;frontend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasFrontendChanges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;commands&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cd frontend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requiresReinstallInFrontend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;change&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;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;frontend/package&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
       &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requiresReinstallInFrontend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;commands&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;npm install&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;commands&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;npm run build&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;commands&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;npm start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Join the whole command string with &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; and run it.
&lt;/li&gt;
&lt;/ol&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;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &amp;amp;&amp;amp; &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;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Command to run:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// exec from child_process&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Let's put it to test! We commit with the message &lt;code&gt;deploy: test&lt;/code&gt; and we see the message:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   Command to run: &lt;span class="nb"&gt;cd&lt;/span&gt; /home/kreta/work/misc/webhook-example &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git pull &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git checkout main &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;npm start&lt;/code&gt; in the &lt;code&gt;package.json&lt;/code&gt; starts the server in &lt;code&gt;localhost:8080&lt;/code&gt;. And sure enough:&lt;br&gt;
   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/2022-10-05-23-08-39.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/2022-10-05-23-08-39.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It's a hack at the end of the day
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The performance cost is way less than GH Action runners. We run a separate Node.js server for this which only takes up like &lt;code&gt;50 MB&lt;/code&gt; of RAM. I'm sure we can remove all the fluff from there and make it leaner but it works for now. &lt;/li&gt;
&lt;li&gt;For multi-repo systems, you can create organisation-level webhooks and change the command according to the &lt;code&gt;repository&lt;/code&gt; field in the payload.&lt;/li&gt;
&lt;li&gt;"But Abhijit, there's no CI at all!". Just add an &lt;code&gt;npm test&lt;/code&gt; somewhere and log the reports, email, etc. if you care about it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Addressing the obvious thoughts in your head, yes, it can break and there's no way of knowing if the command is faulty. But you can setup logging, alerts etc. It's your system. It's code. It cannot get more &lt;a href="https://en.wikipedia.org/wiki/Infrastructure_as_code" rel="noopener noreferrer"&gt;IaC&lt;/a&gt; than this. I set this up on the actual server almost 2 years ago and it hasn't been changed ever since. As you can see, this is a setup once and forget kinda system.&lt;/p&gt;

&lt;p&gt;But if your infra is changing a lot of times and requires really good monitoring, please don't use this. This is a hack and I'm not very fond of hacks. Except for this one. This one, I'm proud of.&lt;/p&gt;

&lt;h2&gt;
  
  
  First principles are good
&lt;/h2&gt;

&lt;p&gt;The simplest &lt;em&gt;solutions&lt;/em&gt; are the best ones. If we go backwards from a solution to the problem, we can find  better ways of thinking. Some hacks and workarounds can sometimes go against the practice of using the right tools and can feel like reinventing the wheel. But if the trade-off is worth it, maybe it is the best solution for it after all. Remember to &lt;a href="https://zerodha.tech/blog/scaling-with-common-sense/" rel="noopener noreferrer"&gt;scale with common sense&lt;/a&gt;.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;The repository was larger than needed because it had a whole Bootstrap theme template. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>github</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Node.js Import Aliases</title>
      <dc:creator>Abhijit Hota</dc:creator>
      <pubDate>Tue, 05 Jul 2022 11:39:43 +0000</pubDate>
      <link>https://forem.com/kretaceous/nodejs-import-aliases-41eb</link>
      <guid>https://forem.com/kretaceous/nodejs-import-aliases-41eb</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Originally published on &lt;a href="https://abhijithota.me/posts/node-import-aliases/"&gt;abhijithota.me&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Oftentimes, as a Node.js codebase grows, this happens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserModel&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../../../db/models/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;validate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../../../lib/utils.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SERVICE_API_KEY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../../../lib/constants.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a few problems with this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sensitivity to folder structure changes&lt;/strong&gt;: A good IDE or editor can auto-import but not all of them are without errors. Also, what if you change something outside your general IDE?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clutter&lt;/strong&gt;: It just simply looks bad&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;A new field in &lt;code&gt;package.json&lt;/code&gt; called &lt;code&gt;imports&lt;/code&gt; was &lt;strong&gt;stabilized in Node.js v14&lt;/strong&gt;. It was introduced earlier in Node.js v12. It follows certain rules and lets you "map" certain aliases (custom paths) to a path of your choice and also declare fallbacks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nodejs.org/docs/latest-v14.x/api/packages.html#packages_imports"&gt;Here's the documentation&lt;/a&gt; for the same.&lt;/p&gt;

&lt;p&gt;We can solve our example problem by adding this to our &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"imports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"#models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src/db/models/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"#utils"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src/lib/utils.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"#constants"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src/lib/constants.js"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and use them in your code anywhere 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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserModel&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#models&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Validate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#utils&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SERVICE_API_KEY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#constants&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Note
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The entries in the &lt;code&gt;imports&lt;/code&gt; field of &lt;code&gt;package.json&lt;/code&gt; must be strings starting with &lt;code&gt;#&lt;/code&gt; to ensure they are disambiguated from package specifiers like &lt;code&gt;@&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The values should be relative paths from the root of the project. The root is where your &lt;code&gt;package.json&lt;/code&gt; is.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the above example, we assumed &lt;code&gt;package.json&lt;/code&gt; was at the root and all the relevant files were inside a &lt;code&gt;src&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;You should see your application run fine but your IDE of choice may show some errors. Undesirable red and yellow squiggles are no one's favorite. It would also auto-import from the actual relative path instead of the path alias. That's no fun.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;jsconfig.json&lt;/code&gt; to the rescue&lt;/strong&gt;. (&lt;code&gt;tsconfig.json&lt;/code&gt; if you're in a TypeScript project.)&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;jsconfig.json&lt;/code&gt;, add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"baseUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"paths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"#models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./src/db/models/index.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"#utils"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./src/lib/utils.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"#constants"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./src/lib/constants.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The above configuration tells your IDE's LSP to look for code in the given prefixes. &lt;a href="https://www.typescriptlang.org/tsconfig#paths"&gt;Refer to the documentation&lt;/a&gt; of the property to know more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we have sweet auto-imports from the desired location:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FFVrqVbM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./2022-07-05-16-45-49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FFVrqVbM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./2022-07-05-16-45-49.png" alt="Screenshot of auto-import working desirably" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fallback dependencies
&lt;/h2&gt;

&lt;p&gt;As seen in the &lt;a href="https://nodejs.org/docs/latest-v14.x/api/packages.html#packages_subpath_imports"&gt;documentation&lt;/a&gt;, you can also use this property for conditionally setting up fallback packages or polyfills. From the documentation:&lt;/p&gt;

&lt;blockquote&gt;

&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"imports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"#dep"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dep-node-native"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./dep-polyfill.js"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dep-node-native"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.0.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;[Here, if the] import &lt;code&gt;#dep&lt;/code&gt; does not get the resolution of the external package &lt;code&gt;dep-node-native&lt;/code&gt; (including its exports in turn), and instead gets the local file &lt;code&gt;./dep-polyfill.js&lt;/code&gt; relative to the package in other environments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Frontend projects
&lt;/h2&gt;

&lt;p&gt;I haven't tried this approach with frontend applications. They generally use a bundling system like Webpack or Rollup which have their own way of resolving aliases. For example, for &lt;a href="https://vitejs.dev/"&gt;Vite&lt;/a&gt; (which uses Rollup and ESBuild), you should add this to your &lt;code&gt;vite.config.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;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="c1"&gt;//   Some other config&lt;/span&gt;
    &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;"&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;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src&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;and in your &lt;code&gt;jsconfig.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"baseUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"paths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"#/*"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above configuration maps everything starting with &lt;code&gt;#&lt;/code&gt; to immediate folders and files below &lt;code&gt;src&lt;/code&gt;. YMMV.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A designer knows he has arrived at perfection not when there is no longer anything to add but when there is no longer anything to take away&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;- Jon Bentley in Programming Pearls&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>guides</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Nerd-sniping myself over Go range expressions</title>
      <dc:creator>Abhijit Hota</dc:creator>
      <pubDate>Sat, 02 Jul 2022 11:33:48 +0000</pubDate>
      <link>https://forem.com/kretaceous/nerd-sniping-myself-over-go-range-expressions-2lcf</link>
      <guid>https://forem.com/kretaceous/nerd-sniping-myself-over-go-range-expressions-2lcf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Originally published on &lt;a href="https://abhijithota.me/posts/nerd-sniping-myself-over-go-range-expressions/"&gt;abhijithota.me&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The background
&lt;/h2&gt;

&lt;p&gt;I stumbled across a situation while writing a Golang project where I needed to loop over a slice returned by a function. &lt;br&gt;
The function being &lt;a href="https://pkg.go.dev/strings#Split"&gt;&lt;code&gt;strings.Split&lt;/code&gt;&lt;/a&gt;. No big deal. I wrote the following:&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Something()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's another way of writing the same thing:&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="n"&gt;splitPath&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;splitPath&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Something()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To the novice-eyed, like me, it would seem the latter was an &lt;em&gt;optimized&lt;/em&gt; version as the function is only called once before the loop and hence more &lt;em&gt;performant&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;I did not care about the negligible performance gain I would get as the &lt;code&gt;path&lt;/code&gt; variable passed to the split function would be limited in length by application constraints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But what if it wasn't?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;tldr; It doesn't matter how you write it. They are both the same. &lt;br&gt;
From the &lt;a href="https://go.dev/ref/spec#For_range"&gt;Golang spec&lt;/a&gt;, &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The range expression x is evaluated once before beginning the loop, with one exception: if at most one iteration variable is present and len(x) is constant, the range expression is not evaluated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This seems obvious once you know about it because it's such a low-hanging fruit for the compiler. It's not even compiler optimization. It's compiler duty.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;p&gt;From here, I'm going to write about how I &lt;a href="https://xkcd.com/356/"&gt;nerd-sniped&lt;/a&gt; myself into finding the answer to this and naturally, spent around 4 hours benchmarking, trying to figure out assembly, checking the compiler optimization wiki, some trivial experimentation that confirmed my theory and one line in the spec that made it all come together.&lt;/p&gt;

&lt;p&gt;Before we proceed into this, have some context about the original scenario. The function should split a separated string called &lt;code&gt;path&lt;/code&gt; with &lt;code&gt;/&lt;/code&gt; as delimiter and extract all integers into an array like this:&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ExtractInts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pathIds&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&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;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;pathIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pathIds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pathIds&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benchmarking the two functions
&lt;/h2&gt;

&lt;p&gt;I put together a quick small project to bench the thing consisting of &lt;code&gt;main.go&lt;/code&gt; and &lt;code&gt;main_test.go&lt;/code&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;main.go&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&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;"strconv"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&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;WithOptim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pathIds&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;pathIdsStr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;pathIdsStr&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;v&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;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;pathIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pathIds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pathIds&lt;/span&gt;&lt;span class="p"&gt;)&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;WithoutOptim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pathIds&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&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;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;pathIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pathIds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pathIds&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;
  
  
  &lt;code&gt;main_test.go&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&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;"strings"&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&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;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"734/956/831/811/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="n"&gt;_000&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;resultWithOptim&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;BenchmarkWithOptim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&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;r&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WithOptim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;resultWithOptim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&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;resultWithoutOptim&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;BenchmarkWithoutOptim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&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;r&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WithoutOptim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;resultWithoutOptim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The variables &lt;code&gt;r&lt;/code&gt;, &lt;code&gt;resultWithOptim&lt;/code&gt; and &lt;code&gt;resultWithoutOptim&lt;/code&gt; are needed to escape compiler optimizations and get reliable benchmarks. &lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go"&gt;this section&lt;/a&gt; from the &lt;a href="https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go#compiler-optimisation"&gt;awesome benchmarking article&lt;/a&gt; by Dave Cheney.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;I ran the benchmark a couple of times.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;In most cases, it was neck-and-neck:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;BenchmarkWithoutOptim-8     63   18067614 ns/op
BenchmarkWithOptim-8        64   17833483 ns/op
3.282s

BenchmarkWithoutOptim-8     64   17879142 ns/op
BenchmarkWithOptim-8        66   17943536 ns/op
3.287s

BenchmarkWithoutOptim-8     66   17915000 ns/op
BenchmarkWithOptim-8        66   17567501 ns/op
3.292s

BenchmarkWithoutOptim-8     56   18344452 ns/op
BenchmarkWithOptim-8        57   17649186 ns/op
2.090s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In some cases the one with &lt;em&gt;optimizations&lt;/em&gt; performed better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;BenchmarkWithoutOptim-8     64   18446009 ns/op
BenchmarkWithOptim-8        73   18054308 ns/op
3.548s

BenchmarkWithoutOptim-8     63   18466071 ns/op
BenchmarkWithOptim-8        70   18600002 ns/op
3.422s

BenchmarkWithOptim-8        64   18917323 ns/op
BenchmarkWithoutOptim-8     58   18092279 ns/op
3.215s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But in some cases the one without any &lt;em&gt;optimizations&lt;/em&gt; performed faster!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;BenchmarkWithOptim-8        55   18848131 ns/op
BenchmarkWithoutOptim-8     68   19239865 ns/op
2.395s

BenchmarkWithOptim-8        57   18323290 ns/op
BenchmarkWithoutOptim-8     63   17598465 ns/op
2.206s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Digging into the why
&lt;/h2&gt;

&lt;p&gt;The first resource I came across was the &lt;a href="https://github.com/golang/go/wiki/CompilerOptimizations"&gt;Compiler And Runtime Optimizations wiki&lt;/a&gt; which stated nothing about such behaviour. &lt;/p&gt;

&lt;p&gt;I also tried converting the code into Assembly using &lt;a href="https://go.godbolt.org/"&gt;Compiler Explorer&lt;/a&gt; but couldn't understand any of it. &lt;/p&gt;

&lt;p&gt;Was the compiler calling the function only once? Are the 2 ways of writing same? I had no way of knowing. Then I thought of something so trivial I felt dumb.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trivial experiment
&lt;/h2&gt;

&lt;p&gt;Consider the following code:&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Nums&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Nums called&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&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="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&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;Loop&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="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;Nums&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&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;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;Loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And surely enough, &lt;code&gt;Nums called&lt;/code&gt; is only printed once to &lt;code&gt;STDOUT&lt;/code&gt;. &lt;br&gt;
This felt so obvious once I realised it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eureka + Facepalm moment
&lt;/h2&gt;

&lt;p&gt;Googling &lt;strong&gt;"go range internals"&lt;/strong&gt; gave me &lt;a href="https://garbagecollected.org/2017/02/22/go-range-loop-internals/"&gt;this article by Robbie V&lt;/a&gt; which sent me to the &lt;a href="https://go.dev/ref/spec#For_range"&gt;Go language specification&lt;/a&gt; where I found this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The range expression x is evaluated once before beginning the loop, with one exception: if at most one iteration variable is present and len(x) is constant, the range expression is not evaluated. &lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;There's nothing much to conclude but there's a lesson to learn. In Robbie V's article, the Step 1 was to &lt;a href="https://en.wikipedia.org/wiki/RTFM"&gt;RTFM&lt;/a&gt;.Unlike that, I dove right into benchmarking which was like comparing two sum functions which returned &lt;code&gt;a + b&lt;/code&gt; vs. &lt;code&gt;b + a&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I discovered a lot but this shouldn't have taken so much of my time. It's a reminder on how we can take some slightly interesting things, like the one I talked about here, for granted and never realise the machinery of it.&lt;/p&gt;

&lt;p&gt;As to which function is better to write, that would be an opinion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other languages
&lt;/h2&gt;

&lt;p&gt;I tried the same thing in a few other languages I've coded in because I never realised this:&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&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;nums&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Nums called&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;loop&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;const&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&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;loop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Nums called"&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Using &lt;code&gt;go test -bench=. -run=xxx&lt;/code&gt; ↩&lt;/p&gt;

&lt;p&gt;Specs: &lt;br&gt;
goos: linux &lt;br&gt;
goarch: amd64 &lt;br&gt;
cpu: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz&lt;/p&gt;

&lt;p&gt;Order of function execution was changed a few times.&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>go</category>
      <category>rtfm</category>
      <category>benchmarking</category>
      <category>internals</category>
    </item>
    <item>
      <title>The Unofficial Dev.to CLI</title>
      <dc:creator>Abhijit Hota</dc:creator>
      <pubDate>Tue, 15 Jun 2021 08:29:23 +0000</pubDate>
      <link>https://forem.com/kretaceous/the-unofficial-dev-to-cli-4bfk</link>
      <guid>https://forem.com/kretaceous/the-unofficial-dev-to-cli-4bfk</guid>
      <description>&lt;h1&gt;
  
  
  The Dev.to CLI
&lt;/h1&gt;

&lt;p&gt;Hello, everyone. &lt;/p&gt;

&lt;p&gt;A few months ago, around the first week of December 2020, I started working on this project. The project was a CLI app which used the &lt;a href="https://docs.forem.com/api"&gt;Dev.to API&lt;/a&gt; to communicate with the website. I got caught up with other things and couldn't finish the project as I wanted to before making it public in front of the Dev.to community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Today, I put the project in community's hands, seeking for reviews, help and in hopes of making it better and usable.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/abhijit-hota/dev-to-cli"&gt;GitHub Repo&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This project is a work in progress. Bear with the useless dependencies, &lt;del&gt;bad&lt;/del&gt; no documentation and half-implemented features.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Roadmap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Post a markdown file as an article with front matter validation.&lt;/li&gt;
&lt;li&gt;✅ Get user's published and unpublished articles&lt;/li&gt;
&lt;li&gt;✅ Get followers&lt;/li&gt;
&lt;li&gt;✅ Get user's reading list and navigate to browser&lt;/li&gt;
&lt;li&gt;✅ Use the Dev.to API key to authorize &lt;/li&gt;
&lt;li&gt;❌ Get and cache user info&lt;/li&gt;
&lt;li&gt;❌ Read articles in terminal&lt;/li&gt;
&lt;li&gt;❌ Get podcast episodes&lt;/li&gt;
&lt;li&gt;❌ Use OAuth to authorize &lt;/li&gt;
&lt;li&gt;❌ Tests?&lt;/li&gt;
&lt;li&gt;❌ Consistent API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;P.S. This article is posted using the &lt;a href="https://github.com/abhijit-hota/dev-to-cli"&gt;dev-to-cli&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>dev</category>
      <category>node</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Suggest me the right Linux distro</title>
      <dc:creator>Abhijit Hota</dc:creator>
      <pubDate>Sun, 15 Nov 2020 09:55:40 +0000</pubDate>
      <link>https://forem.com/kretaceous/suggest-me-the-right-linux-distro-4ane</link>
      <guid>https://forem.com/kretaceous/suggest-me-the-right-linux-distro-4ane</guid>
      <description>&lt;p&gt;Hello, good people of Dev! I need some help from the Linux users out there.&lt;/p&gt;

&lt;p&gt;I've been thinking to switch to Linux (again) after being fed up (again) with Windows' constant lagging on my PC. I'm a web developer and just want a distro which is performant, good looking and has an abundancy of all the required packages (without any workarounds).&lt;/p&gt;

&lt;p&gt;The distros in the banner are the ones I've been considering. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Linux Mint Cinnamon&lt;/strong&gt;: I've heard it's &lt;a href="https://nolanlawson.com/2020/05/10/linux-on-the-desktop-as-a-web-developer/"&gt;very good for web development&lt;/a&gt;. It's lightweight and performant and I've heard some good things about Cinnamon. I've used Mint in the past (like 5-6 years ago).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;del&gt;&lt;strong&gt;Ubuntu 20.04&lt;/strong&gt;&lt;/del&gt;: I've used Ubuntu and have been considering it only for: familiarity and availability of a large user-base. My main pet-peeves while using Ubuntu 18.04 were the unavailability of these following features: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Windows, the clipboard is at my disposal when I pressed &lt;code&gt;Win + v&lt;/code&gt;. I didn't really search for a clipboard manager that does this.&lt;/li&gt;
&lt;li&gt;Blue light filter. I tried using Redshift but for some reason, I couldn't get it to work.&lt;/li&gt;
&lt;li&gt;Hibernation&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;del&gt;&lt;strong&gt;Manjaro&lt;/strong&gt;&lt;/del&gt;: I don't know anything about it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;del&gt;&lt;strong&gt;Peppermint OS&lt;/strong&gt;&lt;/del&gt;: I was considering it because some people claim it to be super performant. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pop!_OS&lt;/strong&gt;: Super pretty! Lots of support for it on the comments below! I'll probably end up using this.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, suggest me anything that you think will suit me! &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Development&lt;/li&gt;
&lt;li&gt;Kinda done with the &lt;em&gt;lag-ful&lt;/em&gt; experience in Windows.&lt;/li&gt;
&lt;li&gt;Will run on Dual boot alongside Windows (which I'll mainly use for Photoshop, Premiere, etc).&lt;/li&gt;
&lt;li&gt;Wants small important features which were mentioned as pet peeves of Ubuntu above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Laptop Specs&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 TB &lt;strong&gt;HDD&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Intel Core i5 8th Gen @1.60GHz&lt;/li&gt;
&lt;li&gt;8GB RAM&lt;/li&gt;
&lt;li&gt;Nvidia GeForce MX130&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;em&gt;Edit: add laptop specs&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Update
&lt;/h3&gt;

&lt;p&gt;Thank you everyone for the suggestions and inputs! By far I've cut the list short to &lt;strong&gt;Mint Cinnamon&lt;/strong&gt; and &lt;strong&gt;Pop!_OS&lt;/strong&gt;. I looked at Fedora too but as I'm not really familiar with it, I doubt if I'll be using it.&lt;/p&gt;

&lt;p&gt;Thanks for your inputs on &lt;strong&gt;Manjaro&lt;/strong&gt; and letting me know about other cool distros like &lt;strong&gt;Zorin OS&lt;/strong&gt; and &lt;strong&gt;Elementary OS&lt;/strong&gt;. I'll surely try them out in the future!&lt;/p&gt;

&lt;p&gt;P.S. I researched a bit and found out that the hibernating feature is not available out of the box in any Linux distribution(?).&lt;/p&gt;

&lt;h3&gt;
  
  
  Update: Aug 2021
&lt;/h3&gt;

&lt;p&gt;I bought an SSD &lt;em&gt;and&lt;/em&gt; shifted to &lt;strong&gt;Linux Mint&lt;/strong&gt; and have been using it for a month.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I don't miss the hibernate feature because booting &amp;amp; shutting down takes less than 10 seconds&lt;/li&gt;
&lt;li&gt;I use &lt;a href="https://hluk.github.io/CopyQ/"&gt;CopyQ&lt;/a&gt; for clipboard management&lt;/li&gt;
&lt;li&gt;Yet to find a Redshift alternative that can be turned on at any time and not just during the night&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks everyone for the inputs!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>linux</category>
      <category>help</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Can open-source documentations be monetized?</title>
      <dc:creator>Abhijit Hota</dc:creator>
      <pubDate>Sat, 12 Sep 2020 02:52:02 +0000</pubDate>
      <link>https://forem.com/kretaceous/can-open-source-documentations-be-monetized-4fla</link>
      <guid>https://forem.com/kretaceous/can-open-source-documentations-be-monetized-4fla</guid>
      <description>&lt;p&gt;I came across an Android app called &lt;strong&gt;Node.js Docs&lt;/strong&gt; by an organisation named &lt;strong&gt;NextLabs.cc&lt;/strong&gt;. &lt;a href="https://play.google.com/store/apps/details?id=cc.nextlabs.nodejs"&gt;Here is the app in Google Play store&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And to my surprise, they have monetized the contents! &lt;/p&gt;

&lt;p&gt;Specifically, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are banner ads in the app.&lt;/li&gt;
&lt;li&gt;To access the documentation of each version &lt;em&gt;for one day&lt;/em&gt;, you need to watch a 15 second video.&lt;/li&gt;
&lt;li&gt;You can buy the whole app for a very little amount but it's monetization nonetheless.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't know much about open-source licenses and monetization so I wanted to ask it here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this legal?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd like to know more about licenses and how all these work.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>documentation</category>
      <category>discuss</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>MovieDex - My first React project!</title>
      <dc:creator>Abhijit Hota</dc:creator>
      <pubDate>Thu, 06 Aug 2020 12:13:36 +0000</pubDate>
      <link>https://forem.com/kretaceous/moviedex-my-first-react-project-1o7h</link>
      <guid>https://forem.com/kretaceous/moviedex-my-first-react-project-1o7h</guid>
      <description>&lt;h3&gt;
  
  
  A React and Node.js app that searches for movies using the TMDB and OMDB database ⚛✨🎥. Try it out here: &lt;a href="https://moviedex.js.org/"&gt;MovieDex&lt;/a&gt;
&lt;/h3&gt;

&lt;h2&gt;
  
  
  The Project
&lt;/h2&gt;

&lt;p&gt;I came across this article: &lt;a href="https://dev.to/simonholdorf/9-projects-you-can-do-to-become-a-frontend-master-in-2020-n2h"&gt;9 Projects you can do to become a Frontend Master in 2020&lt;/a&gt; while I was browsing around Dev and I wanted to build the first one in the list and so I did! &lt;/p&gt;

&lt;p&gt;I made the first prototype in a single sitting. My app was able to search for movies and display them. Great! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But I wanted to amp things up!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I thought what if you even showed the movies details in form of modals?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://searchmoviedex.herokuapp.com/"&gt;And here you are&lt;/a&gt;, an app that searches movies and gives you the relevant details!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tIG_viWx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/689ab7wqhv7bf8lf114x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tIG_viWx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/689ab7wqhv7bf8lf114x.png" alt="MovieDex full screen desktop"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x-NRFjA8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/99461kgflphqxwk6o3s1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x-NRFjA8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/99461kgflphqxwk6o3s1.jpg" alt="MovieDex search"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jEJ3LNfs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y5fny28jcd6ei38sf5vg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jEJ3LNfs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y5fny28jcd6ei38sf5vg.jpg" alt="MovieDex information modal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Powered by ✨
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en"&gt;Node.js&lt;/a&gt; : A server for handling all the API calls to the TMDB and OMDB API. I did not implement the calls in the client side as they involved calling with secret API keys.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://reactjs.org/"&gt;React &lt;/a&gt; : What I really focused on in this project. ⚛💙&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://material-ui.com/"&gt;Material-UI&lt;/a&gt; : Absolutely loved the components! Some of the components I've used in this project are: Card, TextField, Dialog and my personal favorite, Skeleton loaders.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.themoviedb.org/"&gt;The Movie Database&lt;/a&gt; : For searching the movies.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.omdbapi.com/"&gt;Open Movie Database API&lt;/a&gt; : For extensive data. (Ratings were not provided by TMDB API).&lt;/li&gt;
&lt;li&gt;Logo by me. Font used: &lt;a href="https://www.behance.net/gallery/15451401/BLANKA-Free-font"&gt;BLANKA&lt;/a&gt;. Some Photoshopping around and Ta-da! 😂&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Some background about my React journey:
&lt;/h2&gt;

&lt;p&gt;I started learning React in the beginning of July, I guess? &lt;br&gt;
My learning sources included &lt;a href="https://www.youtube.com/playlist?list=PLC3y8-rFHvwgg3vaYJgHGnModB54rxOk3"&gt;the awesome React tutorial&lt;/a&gt; by &lt;a href="https://www.youtube.com/c/Codevolution/"&gt;Codevolution&lt;/a&gt; on YouTube and the &lt;a href="https://reactjs.org/docs/"&gt;official React docs&lt;/a&gt; and some random but highly insightful blog posts by various authors.&lt;/p&gt;

&lt;p&gt;I highly recommend the above mentioned tutorial.&lt;/p&gt;

&lt;p&gt;I hope to make better and bigger things in the future! Continually learning and improving. If you like the project, please consider giving it a star on GitHub and sharing!😇 Any suggestions and feedback is greatly appreciated. 😄 &lt;/p&gt;

&lt;p&gt;In case you missed the links,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://moviedex.js.org/"&gt;here is the app deployed on Heroku&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abhijit-hota/MovieDex"&gt;here is the GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay safe! =)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update: Thanks to the people at &lt;a href="https://js.org/"&gt;js.org&lt;/a&gt; for giving Moviedex a neat domain!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>beginners</category>
      <category>react</category>
      <category>node</category>
    </item>
    <item>
      <title>Can you help me review my MEN stack app?</title>
      <dc:creator>Abhijit Hota</dc:creator>
      <pubDate>Mon, 13 Jul 2020 14:32:34 +0000</pubDate>
      <link>https://forem.com/kretaceous/can-you-help-me-review-my-men-stack-app-28og</link>
      <guid>https://forem.com/kretaceous/can-you-help-me-review-my-men-stack-app-28og</guid>
      <description>&lt;p&gt;&lt;strong&gt;You can find the app &lt;a href="https://github.com/abhijit-hota/Node-Notes"&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I've been learning Node.js for the past few months and I recently deployed my first MEN stack app on Heroku. The app lacks a UI as I wanted to focus on the backend part.&lt;/p&gt;

&lt;p&gt;The reason I'm writing this post is because I want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure that I am following, if not all, but some of the best Node.js practices.&lt;/li&gt;
&lt;li&gt;Know how well my approaches to the problems are and how can I improve them. Feedback on the directory structure, code modularisation, styling, etc. will be helpful.&lt;/li&gt;
&lt;li&gt;Know what can I do to make my app more of a 'production-level' app.&lt;/li&gt;
&lt;li&gt;Know something that I don't know I don't know!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;README&lt;/code&gt; file in the &lt;a href="https://github.com/abhijit-hota/Node-Notes"&gt;GitHub repository&lt;/a&gt; for the app provides a good overview of the app. &lt;/p&gt;

&lt;h2&gt;
  
  
  Any help will be appreciated 😄.
&lt;/h2&gt;

&lt;p&gt;P.S. This is my first post on Dev.to &lt;/p&gt;

</description>
      <category>help</category>
      <category>node</category>
      <category>mongodb</category>
      <category>review</category>
    </item>
  </channel>
</rss>
