<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Josh Cole</title>
    <description>The latest articles on DEV Community by Josh Cole (@saikojosh).</description>
    <link>https://dev.to/saikojosh</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%2F392249%2F22f34ac8-fd26-4689-ab33-660685c92764.jpg</url>
      <title>DEV Community: Josh Cole</title>
      <link>https://dev.to/saikojosh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/saikojosh"/>
    <language>en</language>
    <item>
      <title>How to Publish an NPM Package from a GitLab CI/CD Pipeline</title>
      <dc:creator>Josh Cole</dc:creator>
      <pubDate>Wed, 08 Jun 2022 22:00:54 +0000</pubDate>
      <link>https://dev.to/saikojosh/how-to-publish-an-npm-package-from-a-gitlab-cicd-pipeline-2p83</link>
      <guid>https://dev.to/saikojosh/how-to-publish-an-npm-package-from-a-gitlab-cicd-pipeline-2p83</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Take a look at the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; configuration file in my recent &lt;a href="https://gitlab.com/SaikoJosh/safe-env-vars" rel="noopener noreferrer"&gt;safe-env-vars&lt;/a&gt; project. This shows how I configured GitLab’s built-in CI/CD pipelines to automatically build and publish the package to npm. This post will explain the steps required to set this up in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s in a pipeline?
&lt;/h2&gt;

&lt;p&gt;Long before GitHub joined the party with GitHub Actions it was possible to run continuous integration and deployment (CI/CD) workloads on GitLab. For the best part of a decade now, we’ve been able to use the same tool that hosts our code repositories to run our pipelines. I was previously a big fan of &lt;a href="https://circleci.com/" rel="noopener noreferrer"&gt;Circle CI&lt;/a&gt;, especially when they introduced support for Docker containers, but I haven’t needed to use these guys in years.&lt;/p&gt;

&lt;p&gt;But why do we care about CI/CD pipelines in the first place? Well, continuous integration (CI) and continuous deployment (CD) are essential for ensuring software quality and agility in distributed teams. They allow us to run automated quality checks, execute our test suites, scan for security vulnerabilities, publish and deploy our apps, and a myriad of other important tasks. They’re also great at saving time on small projects such as npm packages!&lt;/p&gt;

&lt;p&gt;At a high level, CI/CD pipelines cover these areas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Building&lt;/strong&gt; — Installing dependencies, compiling your code or application, and anything else required to prepare your project for testing and deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verifying&lt;/strong&gt; — Performing static analysis of your codebase, assets, and compiled artifacts to ensure they meet quality and security standards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing&lt;/strong&gt; — Executing your test suite to confirm everything works as expected and no bugs have crept in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploying&lt;/strong&gt; — Publishing your package or deploying your application to the cloud.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reporting&lt;/strong&gt; — Providing insight into build errors, development velocity, security vulnerabilities, and a lot more.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What’s in a GitLab pipeline?
&lt;/h2&gt;

&lt;p&gt;Recently I wrote a post about &lt;a href="https://joshuacole.me/thoughts/youre-doing-environment-variables-all-wrong-b225358b-3890-5713-aa00-57debcd489a5" rel="noopener noreferrer"&gt;environment variables&lt;/a&gt; where I discussed an npm package I had published called &lt;a href="https://www.npmjs.com/package/safe-env-vars" rel="noopener noreferrer"&gt;safe-env-vars&lt;/a&gt; — that package is automatically built and published using GitLab CI/CD (and it’s open source) so if you want to skip ahead why not take a browse of its &lt;a href="https://gitlab.com/SaikoJosh/safe-env-vars" rel="noopener noreferrer"&gt;code repository&lt;/a&gt;. The main point of interest for those wishing to skip ahead 🏃💨 is the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file which tells GitLab about the jobs we want to execute in the pipeline.&lt;/p&gt;

&lt;p&gt;Before we can get into the nitty gritty there are a few terms GitLab uses that we ought to define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline&lt;/strong&gt; — A single CI/CD execution consisting of several stages and jobs, typically triggered by a commit or a merge into a specific branch. You can have different pipelines for different purposes, for example, to verify changes in a merge request, or conduct a cloud deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stage&lt;/strong&gt; — A grouping of related jobs that must succeed before GitLab will proceed to the next stage in the pipeline. If there are no further stages, the pipeline will complete successfully.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job&lt;/strong&gt; — A task you define that typically runs in its own idempotent container (e.g. &lt;code&gt;npm run build&lt;/code&gt;, &lt;code&gt;npm publish&lt;/code&gt;, etc). Multiple jobs within the same stage can be run in parallel as they are usually independent of each other.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitLab pipelines are very powerful and can be configured in a lot of different ways. Some features are restricted to the paid and enterprise pricing tiers but all the features we’ll use below are available for free, as long as you have some pipeline minutes remaining! At the time of writing GitLab provides 400 free minutes per month for pipeline execution, which is more than ample for our needs here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our goal
&lt;/h2&gt;

&lt;p&gt;So what are we aiming to do here? When I created the &lt;a href="https://www.npmjs.com/package/safe-env-vars" rel="noopener noreferrer"&gt;safe-env-vars&lt;/a&gt; package I had two goals:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Automatically publish my package to npm whenever I committed or merged into the &lt;code&gt;main&lt;/code&gt; branch so I didn’t need to do this manually.&lt;/li&gt;
&lt;li&gt;Run some code quality checks to catch any silly mistakes. I didn’t want to spend much time setting up these checks so I opted to limit them to code linting and unit testing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our pipeline will consist of three &lt;code&gt;stages&lt;/code&gt; and four &lt;code&gt;jobs&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage Name&lt;/th&gt;
&lt;th&gt;Job Name&lt;/th&gt;
&lt;th&gt;Job Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prepare&lt;/td&gt;
&lt;td&gt;Install&lt;/td&gt;
&lt;td&gt;Runs npm install to install key development dependencies such as TypeScript and Jest, and to build our package using the TS compiler.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verify&lt;/td&gt;
&lt;td&gt;Lint&lt;/td&gt;
&lt;td&gt;Runs ESLint to verify our code meets the agreed linting rules.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Test&lt;/td&gt;
&lt;td&gt;Runs Jest to verify all unit tests pass and nothing has broken.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Publish&lt;/td&gt;
&lt;td&gt;Publish&lt;/td&gt;
&lt;td&gt;Runs npm publish to publish our package to the npm registry.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Our final pipeline will look something like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxm6y99bb6t7ocumpx4rr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxm6y99bb6t7ocumpx4rr.png" alt="Example pipeline"&gt;&lt;/a&gt;  &lt;/p&gt;
&lt;h2&gt;
  
  
  Step by step guide
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Create your package
&lt;/h3&gt;

&lt;p&gt;Before you configure the pipeline you’ll need to have created a package with a suitable &lt;code&gt;package.json&lt;/code&gt; file. Besides including the usual properties such as the dependecnies, author, and so on, you need to make sure the &lt;code&gt;“main”&lt;/code&gt; property points to the JavaScript file which is the entrypoint to your package.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;TypeScript&lt;/strong&gt; projects you’re going to need a few extra bits, but you can ignore these if you’re working with vanilla JavaScript (but why 😭):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;“types”&lt;/code&gt; property should point to the entrypoint for exported type definitions.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;“scripts.build”&lt;/code&gt; property should call the TS compiler, something like &lt;code&gt;"build": "npx tsc --outDir ./dist"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;“scripts.prepublishOnly”&lt;/code&gt; property should look like &lt;code&gt;"prepublishOnly": "npm run build"&lt;/code&gt; in order to automatically build your package before publishing with &lt;code&gt;npm publish&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might end up with a &lt;code&gt;package.json&lt;/code&gt; file looking similar to this:&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;"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;"my-package"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/src/main.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;"types"&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.d.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&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;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx tsc --outDir ./dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx eslint . --ext .ts,.tsx,.js,.jsx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"prepublishOnly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx jest --watch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"test:cov"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx jest --coverage --verbose --runInBand"&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="err"&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;"devDependencies"&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="err"&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;My personal preference is to have additional scripts defined in the package.json for linting (&lt;code&gt;lint&lt;/code&gt;), testing (&lt;code&gt;test&lt;/code&gt;), and testing with coverage (&lt;code&gt;test:cov&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Add an npm ignore file
&lt;/h3&gt;

&lt;p&gt;In the root of your code repository you’ll want to add a file called &lt;code&gt;.npmignore&lt;/code&gt; and within it list all the paths you wish to exclude from your published package. This is important because there are some files you &lt;em&gt;don’t&lt;/em&gt; need to include, and some you definitely &lt;em&gt;shouldn’t&lt;/em&gt; include.&lt;/p&gt;

&lt;p&gt;The syntax is very similar &lt;code&gt;.gitignore&lt;/code&gt; and you might end up with something like the below. This ensures the &lt;code&gt;src&lt;/code&gt; directory doesn’t get included (for TypeScript projects we only want our &lt;code&gt;dist&lt;/code&gt; directory published). It also lists the various configuration files which aren’t important for people to actually use the package in their apps and just add unnecessary weight to a node_modules directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
.gitlab-ci.yml
.eslintignore
.gitignore
.eslintrc.js
.gitmodules
.prettierrc.js
jest.config.mjs
tsconfig.json
dist/**/*.spec.*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Add the CI/CD config file
&lt;/h3&gt;

&lt;p&gt;In the root of your code repository create an empty &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file with the following contents (the full reference for GitLab’s config file is available here: &lt;a href="https://docs.gitlab.com/ee/ci/yaml/" rel="noopener noreferrer"&gt;https://docs.gitlab.com/ee/ci/yaml&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node:16&lt;/span&gt;

&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ARTIFACT_DOWNLOAD_ATTEMPTS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# Number of retries for restoring saved artifacts.&lt;/span&gt;
  &lt;span class="na"&gt;FORCE_COLOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1'&lt;/span&gt; &lt;span class="c1"&gt;# Whether to force colour output in compatible tooling.&lt;/span&gt;
  &lt;span class="na"&gt;GET_SOURCES_ATTEMPTS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# Number of retries for git commands.&lt;/span&gt;
  &lt;span class="na"&gt;GIT_STRATEGY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fetch&lt;/span&gt; &lt;span class="c1"&gt;# How to pull submodules.&lt;/span&gt;
  &lt;span class="na"&gt;GIT_SUBMODULE_STRATEGY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;recursive&lt;/span&gt; &lt;span class="c1"&gt;# How to treat nested git submodules.&lt;/span&gt;
  &lt;span class="na"&gt;RESTORE_CACHE_ATTEMPTS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# Number of retries for restoring cached files.&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;prepare&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;verify&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;publish&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The YAML above is in three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;image&lt;/code&gt; string specifies the Docker image and tag to use (by default) for each of the jobs, in our case Node.js version 16.x. This can be overriden in each individual job later if needed. Advanced developers might want to create and publish their own Docker images with any additional dependencies their pipeline requires.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;variables&lt;/code&gt; dictionary lists the environment variables to make available to each job. These can also be customised for each job. I’ve started you here with some useful variables that customise the behaviour of the pipeline (see the comments beside each for what they do). For example, the &lt;code&gt;FORCE_COLOR&lt;/code&gt; variable is used by many (but not all) tools to force them to output ANSI colour codes even when they can’t detect a TTY device.&lt;/li&gt;
&lt;li&gt;Finally, the &lt;code&gt;stages&lt;/code&gt; array lists the names of each of the three stages that will house our jobs. We will define each of the jobs next.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 4: Add the “install” job
&lt;/h3&gt;

&lt;p&gt;At the bottom of your config file add the following top-level key, &lt;code&gt;install&lt;/code&gt;, which defines the job named “install”. The &lt;code&gt;install.stage&lt;/code&gt; property defines which stage the job belongs to, in this case the “prepare” stage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prepare&lt;/span&gt;
  &lt;span class="na"&gt;interruptible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;deps_$CI_COMMIT_REF_SLUG'&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules/&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;on_success&lt;/span&gt;
    &lt;span class="na"&gt;expire_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;12h&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm config set -- '//registry.npmjs.org/:_authToken' "${NPM_AUTH_TOKEN}"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm install --no-progress --no-audit --no-fund --verbose&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;merge_requests&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full &lt;a href="https://docs.gitlab.com/ee/ci/yaml/" rel="noopener noreferrer"&gt;keyword reference&lt;/a&gt; on GitLab’s website will explain all the various properties defined above, but the important ones to note are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;“artifacts”&lt;/strong&gt; — Tells GitLab which path(s) to hold on to between jobs, in this case, that’s the &lt;code&gt;node_modules&lt;/code&gt; directory as we’ll be running &lt;code&gt;npm install&lt;/code&gt; in this job only, and preserving the installed dependencies for use in subsequent jobs to save time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“script”&lt;/strong&gt; — The lines of the shell script to execute for the job, in this case to set the NPM auth token that allows publishing to the registry. The &lt;code&gt;NPM_AUTH_TOKEN&lt;/code&gt; environment variable should be set in the GitLab UI for your project or group and not comitted to your code repository! You can find the correct page in GitLab by clicking CI/CD in the left-hand menu of any project or group and going to the section titled “variables”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“only”&lt;/strong&gt; — An array listing the events that can trigger the job to be included in the pipeline, in this case we execute the job for merge requests and for commits/merges to the &lt;code&gt;develop&lt;/code&gt; and &lt;code&gt;main&lt;/code&gt; branches. If none of the conditions match, the job will not be included in the pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 5: Add the “lint” job
&lt;/h3&gt;

&lt;p&gt;Add the next job, &lt;code&gt;lint&lt;/code&gt;, at the bottom of the config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Lints the codebase.&lt;/span&gt;
&lt;span class="na"&gt;lint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;verify&lt;/span&gt;
  &lt;span class="na"&gt;interruptible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;install&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm run lint&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;merge_requests&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we have a similar set of properties defining what our job does, including &lt;code&gt;stage&lt;/code&gt;, this time grouping our job in the &lt;code&gt;verify&lt;/code&gt; stage, and &lt;code&gt;script&lt;/code&gt; which simply runs the &lt;code&gt;npm run lint&lt;/code&gt; script we defined in our package.json.&lt;/p&gt;

&lt;p&gt;There is a new property to pay attention to, however. In order to execute our lint script ESLint and its associated dependencies need to be installed. Each CI/CD job is run in a new container and so doesn’t have any of the changes introduced in the preceeding &lt;code&gt;install&lt;/code&gt; job, such as the &lt;code&gt;node_modules&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;In order to bring our installed &lt;code&gt;node_modules&lt;/code&gt; into this &lt;code&gt;lint&lt;/code&gt; job we need to specify the &lt;code&gt;dependencies&lt;/code&gt; array and list our &lt;code&gt;install&lt;/code&gt; job inside it. This will cause GitLab to pull in all the artifacts specified in the install job (i.e. &lt;code&gt;node_modules&lt;/code&gt;) and put them back in the same places they were before. As far as npm will be concerned, the &lt;code&gt;node_modules&lt;/code&gt; directory was always there!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Add the “test” job
&lt;/h3&gt;

&lt;p&gt;Add the next job, &lt;code&gt;test&lt;/code&gt;, at the bottom of the config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Runs the test suite.&lt;/span&gt;
&lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;verify&lt;/span&gt;
  &lt;span class="na"&gt;interruptible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;install&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm run test:cov&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;merge_requests&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once again, our job specifies the &lt;code&gt;install&lt;/code&gt; job as a dependency so the &lt;code&gt;node_modules&lt;/code&gt; directory is available again, and we specify a simple bash script that runs &lt;code&gt;npm run test:cov&lt;/code&gt; - this simply executes our test runner, Jest, with coverage turned on. We also put this job under the &lt;code&gt;verify&lt;/code&gt; stage and it will be run in parallel with the &lt;code&gt;lint&lt;/code&gt; job to save time.&lt;/p&gt;

&lt;p&gt;You might have noticed we specify a property called &lt;code&gt;interruptible: true&lt;/code&gt; which simply tells GitLab it is allowed to kill our pipeline whilst this job is running if needed. This is useful when a new pipeline wants to start (i.e. something new has been committed to the same branch) that would otherwise have to wait for the current pipeline to finish, saving us both time and pipeline minutes!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Add the “publish” job
&lt;/h3&gt;

&lt;p&gt;Add the next job, &lt;code&gt;test&lt;/code&gt;, at the bottom of the config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Publishes the package to npm.&lt;/span&gt;
&lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;publish&lt;/span&gt;
  &lt;span class="na"&gt;interruptible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;install&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm config set -- '//registry.npmjs.org/:_authToken' "${NPM_AUTH_TOKEN}"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm publish --verbose&lt;/span&gt;
  &lt;span class="na"&gt;resource_group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;deployment-$CI_COMMIT_REF_SLUG'&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_DEPLOY_FREEZE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;null'&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;never&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_COMMIT_REF_NAME&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$CI_COMMIT_REF_NAME&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"develop"'&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;never&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"merge_request_event"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$CI_COMMIT_REF_NAME&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"develop"'&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;never&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;on_success&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we set the &lt;code&gt;interruptible&lt;/code&gt; property to &lt;code&gt;false&lt;/code&gt; because we don’t want GitLab to kill the pipeline halfway through a publish, leaving us in a situation where we can’t be sure what state our package is in… did that version get deployed or not? 🙀📦&lt;/p&gt;

&lt;p&gt;We also specify &lt;code&gt;retry: 1&lt;/code&gt; which tells GitLab to retry the job one additional time if it fails. This can be useful in cases where you’re relying on side effects for the job to succeed, for example &lt;code&gt;npm publish&lt;/code&gt; makes HTTP requests to the npm registry which could fail due to transient network faults or a problem on npm’s side. In those cases, we want to automatically retry in case the problem resolves itself.&lt;/p&gt;

&lt;p&gt;The other property of import here is &lt;code&gt;rules&lt;/code&gt; where we list an array of objects. Each object defines a rule for when our publish job should run. We’re using this property instead of &lt;code&gt;only&lt;/code&gt; here because we need to define much more complex behaviour than &lt;code&gt;only&lt;/code&gt; will allow.&lt;/p&gt;

&lt;p&gt;In the above code we have specified four rules and the first rule to match will be applied:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the &lt;code&gt;CI_DEPLOY_FREEZE&lt;/code&gt; environment variable is set, &lt;em&gt;never&lt;/em&gt; execute the publish job.&lt;/li&gt;
&lt;li&gt;If the branch we’re running on isn’t &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;develop&lt;/code&gt;, &lt;em&gt;never&lt;/em&gt; execute the publish job.&lt;/li&gt;
&lt;li&gt;If we’re in the scope of a merge request, &lt;em&gt;never&lt;/em&gt; execute the publish job.&lt;/li&gt;
&lt;li&gt;Otherwise, and if the rest of the pipeline has been successful, then &lt;em&gt;execute&lt;/em&gt; the publish job.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The syntax for &lt;code&gt;rules&lt;/code&gt; is very powerful and allows us to specify a complex set of conditions for when the job should run (or not). There is far more to this than I can possibly detail here, so I encourage you to refer to the GitLab documentation: &lt;a href="https://docs.gitlab.com/ee/ci/yaml/" rel="noopener noreferrer"&gt;https://docs.gitlab.com/ee/ci/yaml&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: Commit and push
&lt;/h3&gt;

&lt;p&gt;Once your package and the GitLab CI/CD config file are ready, you can commit and push your changes up. If everything has gone to plan, you should see a pipeline appear in the GitLab UI for your repository under CI/CD in the left-hand menu. By clicking into the pipeline you can follow through the jobs as they execute, and drill down into the output logs for each individual job.&lt;/p&gt;

&lt;p&gt;Below you can see an example of four pipelines that have been run. The first pipeline at the top of the list is the most recent and was run against the &lt;code&gt;main&lt;/code&gt; branch. The second pipeline down was run on a merge request and does not include the &lt;code&gt;publish&lt;/code&gt; job as the rules we configured exclude it from being included in merge request pipelines.&lt;/p&gt;

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

&lt;p&gt;Clicking into the first pipeline shows the stages and jobs that were executed. As this pipeline was run against the &lt;code&gt;main&lt;/code&gt; branch our rules caused the &lt;code&gt;publish&lt;/code&gt; job to be included and the package was subsequently (and automatically) published to npm. Happy days! 🥳&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05uw0n9583oqlenp18xx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05uw0n9583oqlenp18xx.png" alt="Example pipeline stages and jobs"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;From here if we click into the &lt;code&gt;test&lt;/code&gt; job we can see a snippet of the output emitted by Jest during the job. There is also some other log output which isn’t shown here for brevity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gp6q6u2nvx6388grkos.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5gp6q6u2nvx6388grkos.png" alt="Example job output"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In conclusion, it’s actually very simple to setup a powerful CI/CD pipeline in GitLab, especially if all you’re doing is publishing a package to the npm registry. Pipelines are a great way to verify the quality and robustness of your code, package, or application, and they are a fantastic timesaver when it comes to automatic publishing and deployment. To configure a pipeline in GitLab all you need is a &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file in the root of your repository. You can find the keyword reference for that file on &lt;a href="https://docs.gitlab.com/ee/ci/yaml/" rel="noopener noreferrer"&gt;GitLab’s website&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>gitlab</category>
    </item>
    <item>
      <title>You’re Doing Environment Variables All Wrong - A Node.js Perspective</title>
      <dc:creator>Josh Cole</dc:creator>
      <pubDate>Sun, 08 May 2022 23:43:06 +0000</pubDate>
      <link>https://dev.to/saikojosh/youre-doing-environment-variables-all-wrong-a-nodejs-perspective-20g0</link>
      <guid>https://dev.to/saikojosh/youre-doing-environment-variables-all-wrong-a-nodejs-perspective-20g0</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Environment variables aren’t always what you expect and it’s painful to check each one. Instead, use a library such as &lt;a href="https://www.npmjs.com/package/safe-env-vars"&gt;safe-env-vars&lt;/a&gt; to do the hard work and be safe in the knowledge your environment variables won’t cause you any headaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oh, what?
&lt;/h2&gt;

&lt;p&gt;Environment variables are easy, you say, we’ve been working with environment variables for our entire careers... how could we possibly be “doing them wrong”?! Well, as American computer scientist &lt;a href="https://en.wikipedia.org/wiki/Jim_Horning"&gt;Jim Horning&lt;/a&gt; said, “Nothing is as simple as we hope it will be”. And in this case, a risk is introduced every time you ‘set and forget’ a variable. Let’s explore the problem, or rather, problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s start at the top
&lt;/h2&gt;

&lt;p&gt;So what are environment variables and why do we use them? Put simply, environment variables are pieces of state (read; string values) that we store in the ‘environment’ that our application is running in. This state is usually set via one of the mechanisms provided by the operating system, shell, or container orchestrator, which is responsible for our application process.&lt;/p&gt;

&lt;p&gt;Environment variables are a simple mechanism, and this is good thing because a lot of engineering is not so simple.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Simplicity is prerequisite for reliability. “ — Edsger Dijkstra.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Often in engineering we need to iteratively refactor and rework our solutions until we reach a good balance between readability and functionality. Here, simplicity is our friend because it makes it easier to understand what our code is doing and why. We’re far less likely to end up with misbehaving, buggy software if it’s simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  See, it’s mostly upside!
&lt;/h2&gt;

&lt;p&gt;Well yes, there is an awful lot of upside. As we shall see storing state in the environment allows us to do several very useful things that would otherwise be risky or time consuming.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Change configuration at will
&lt;/h3&gt;

&lt;p&gt;We can change the behaviour of our application whilst avoiding risky activities such as changing source code, and time consuming chores such as re-compiling, re-deploying, testing, and so on. If we need to rotate API keys, turn feature flags on or off, or adjust some other behaviour, we can do all this from the comfort of our chairs simply by deploying the new values and restarting our applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Keep secrets hidden&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We can store secrets separately to our source code. This helps us mitigate the risk of sensitive values such as API keys, credentials, and so on that would put our users at risk if they were to be exposed. This way, if a nefarious actor gains access to our source code, they won’t get their hands on the secrets at the same time. It makes it harder for them to do us damage.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Stay on the right side of regulation
&lt;/h3&gt;

&lt;p&gt;In regulated industries it’s often necessary to limit personnel access to sensitive systems to a limited number of specific people. By storing the secrets separately to the source code, the engineers can still do their jobs effectively without the keys to the kingdom sitting within their reach.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Set different values per engineer or environment
&lt;/h3&gt;

&lt;p&gt;Whilst working locally we often need to use different values for API keys, feature flags, and behaviour flags that make sense whilst developing but not in deployed environments. The same can be said of automated testing where tests may need to change the application’s behaviour and inputs to test particular aspects.&lt;/p&gt;

&lt;p&gt;Each deployed environment can be given a different set of environment variables, for instance to keep production secrets isolated and separate from staging secrets. As with local development, we can also change the values in our staging/testing environments independently of the other environments as needed. Flexibility is great!&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Use dot env files
&lt;/h3&gt;

&lt;p&gt;In the expansive JavaScript universe a common pattern is to use the &lt;a href="https://www.npmjs.com/package/dot-env"&gt;dot-env&lt;/a&gt; package to read in environment variables from a local &lt;code&gt;.env&lt;/code&gt; file that is not committed to the repository. This is a much quicker (and importantly more visible) alternative to setting environment variables in the actual environment. Engineers can change the values quickly and easily whilst developing as the need arises.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what’s the problem?
&lt;/h2&gt;

&lt;p&gt;There are a few. These are all risks that we need to mitigate for, vulnerabilities that can leave us open to attack, and mistakes that can cause unexpected behaviour at the worst times. Even in the best case scenario, badly behaving environment variables can waste a significant amount of time, especially in dynamically typed languages such as JavaScript.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Seek simplicity but distrust it.” — Alfred North Whitehead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We need to be careful not to fall in to one of the myriad traps. In each case, it’s hard if not impossible to predict how our application will behave. Sometimes issues are immediately obvious, but in many instances we won’t know about an issue until it randomly rears its head at the most inconvenient time.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Missing values
&lt;/h3&gt;

&lt;p&gt;The most obvious risk here is that a value could be missing. This is more likely to be the case on our local machines where one developer makes a change that requires an environment variable we haven’t got set in our local environment. It’s less likely to happen in deployed code which has gone through several layers of reviews and testing, but it can still happen with complex systems. We’re only human after all!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"TRACE"&lt;/span&gt;
&lt;span class="c"&gt;#API_KEY="..."&lt;/span&gt;
&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oops, we disabled the &lt;code&gt;API_KEY&lt;/code&gt; value and forgot about it. Or perhaps our colleague added &lt;code&gt;ACCESS_TOKEN_TTL&lt;/code&gt; in their latest commit and you haven’t noticed you need to add it to your local &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Empty values
&lt;/h3&gt;

&lt;p&gt;Similar to missing values, it’s possible for the value of an environment variable to end up as an empty string. Perhaps that was intentional (though it probably shouldn’t be), but how would we know?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What exactly does the above mean to you? Does it mean we want to turn logging off entirely? Does it mean we want to use the default log level and we don’t care what it is? Or (more likely) has something broken that we need to fix? Ask your friends, you might find they have diverging expectations to you.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Arbitrary values
&lt;/h3&gt;

&lt;p&gt;Environment variables are often used for boolean values such as feature flags. Booleans have some big downsides which I won’t go into here, but safe to say those boolean values are arbitrary and different engineers will use different values.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;FEATURE_FLAG_AAA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;
&lt;span class="nv"&gt;FEATURE_FLAG_B&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"TRUE"&lt;/span&gt;
&lt;span class="nv"&gt;FEATURE_FLAG_c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;
&lt;span class="nv"&gt;FEATURE_FLAG_c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Y"&lt;/span&gt;
&lt;span class="nv"&gt;FEATURE_FLAG_c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As humans, we instantly know that all these values all represent the same thing, that a particular feature flag has been toggled on. We rely on conventions and consistency to ensure we don’t fall into the trap of using different values in different places, but good intentions won’t always help when herding cats 🐈 (engineers).&lt;/p&gt;

&lt;p&gt;The same can be said if you use enum values, such as with log levels (&lt;code&gt;INFO&lt;/code&gt;, &lt;code&gt;DEBUG&lt;/code&gt;, &lt;code&gt;TRACE&lt;/code&gt;, etc). Obviously you could end up with an invalid value that may throw a spanner in the works unless you validate the value you read from the variable... but how many of us really do that? 🌚&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Incorrect types
&lt;/h3&gt;

&lt;p&gt;We covered the problem with boolean values above, it’s a similar story if you need to use a value as a number. Environment variables are always read in as strings regardless of what value you’ve stored in them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;FEATURE_FLAG_AAA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;
&lt;span class="nv"&gt;SOME_NUMBER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"3"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maybe you need the &lt;code&gt;SOME_NUMBER&lt;/code&gt; value to be a number so TypeScript will allow you to pass it to the nice library you want to use. Do you parse the value to an integer like this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SOME_NUMBER&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;someNiceLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And what if that value gets changed to a float in one environment but not another?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SOME_NUMBER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"3.14"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suddenly your application is freaking out but you don’t know why. Your seeing some weird behaviour but you don’t know why, or perhaps worse, you’re seeing an error message stack trace that is a red herring and points you totally in the wrong direct for an hour whilst your customer is yelling at you.&lt;/p&gt;

&lt;p&gt;You might argue that this issue is more likely to occur in JavaScript than other languages, but unexpected behaviour is always a risk when dealing with side effects like environment variables.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Optional values
&lt;/h3&gt;

&lt;p&gt;Another consideration is that sometimes we really do want values to be optional, where things like the following may be totally valid given our context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#FEATURE_FLAG_AAA="true" # 1. comment out a value we don't need at the moment.&lt;/span&gt;
&lt;span class="nv"&gt;FEATURE_FLAG_AAA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="c"&gt;# 2. or set it to an empty value (not so good!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we’re manually checking environment variables to ensure they exist we need to leave this one variable unchecked as it may be optional. This introduces the human element whereby future engineers may not add in presence checks where needed because they see they aren’t consistently applied to all variables. The variable is &lt;strong&gt;implicitly&lt;/strong&gt; optional and this leaves it open to interpretation by the reader. Better to be explicit when variables are optional as the majority (i.e. the default) will be required.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Hidden environment variables
&lt;/h3&gt;

&lt;p&gt;It’s a poor (but sadly common) practice for engineers to read in an environment variable at the point they want to use it, for instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;calculateCommission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&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;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COMMISSION_RATE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What’s the problem here? Well our nice &lt;code&gt;calculateCommission&lt;/code&gt; function can exhibit odd behaviour if our &lt;code&gt;COMMISSION_RATE&lt;/code&gt; environment variable is missing or set to some weird value. Perhaps the engineer that wrote this forgot to update the documentation to indicate that the commission rate needs to be configured in the environment and you didn’t realise you needed to do it. Whoops.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Behaviour and security
&lt;/h3&gt;

&lt;p&gt;Environment variables are side effects. You might say they add impurities to our code. Our application can’t control the values it’s reading from the environment and must accept what it’s given. This means environment variables are akin to user input and carry the same risks. ☠️&lt;/p&gt;

&lt;p&gt;The value of an environment variable could be unexpected, or worse, malicious. Best case, the value triggers a visible error that leads you down the garden path for an hour or two before you figure out what’s actually causing the issue. Worst case, you have exposed your application to input you can’t trust (and you have trusted it &lt;em&gt;absolutely&lt;/em&gt;) without verifying it’s authenticity or correctness, and now you have been storing sensitive data in the attacker’s message queue for the last 2 weeks rather than your own. 😬&lt;/p&gt;

&lt;h2&gt;
  
  
  Right, how do we sidestep these issues?
&lt;/h2&gt;

&lt;p&gt;Simplicity is fantastically splendiferous, except when it’s not.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it's worth it in the end because once you get there, you can move mountains.” — Steve Jobs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The trick as with all ‘user’ input outside our sphere of control, is to trust but verify, or in our case, trust but validate. There are a few things you want to do for every value you read in from the environment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Presence checks&lt;/strong&gt; - ensure expected environment variables are defined.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empty checks&lt;/strong&gt; - ensure expected values are not empty strings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Value checks&lt;/strong&gt; - ensure only expected values can be set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typecasting&lt;/strong&gt; - ensure values are cast to the expected type at the point you read them in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single entry point&lt;/strong&gt; - ensure all variables are pulled in at the same place, and not smeared around your codebase for people to stumble upon later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dot env&lt;/strong&gt; - read values from both a &lt;code&gt;.env&lt;/code&gt; file and the environment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Writing the code to do this for every project would be a pain, but the good news is, I’ve already done that for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Package: safe-env-var
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/safe-env-vars"&gt;safe-env-vars&lt;/a&gt; will read environment variables from the environment as well as a &lt;code&gt;.env&lt;/code&gt; file in a safe way with full TypeScript support. By default, it will throw an error if the environment variable you're trying to read is undefined or empty.&lt;/p&gt;

&lt;p&gt;It’s very quick to get started with basic usage if all you’re doing is reading in string values that are always required:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;EnvironmentReader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;safe-env-vars&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;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EnvironmentReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MY_VALUE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`MY_VALUE`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can explicitly mark variables as optional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MY_VALUE&lt;/span&gt; &lt;span class="o"&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;optional&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`MY_VALUE`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// string | undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you can allow the variables to be an empty value, though I would discourage this for the reasons stated in the discussion above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MY_VALUE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`MY_VALUE`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;allowEmpty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can even cast the type of the value as you’d expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Required&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MY_BOOLEAN&lt;/span&gt; &lt;span class="o"&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;boolean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`MY_BOOLEAN`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// boolean&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MY_NUMBER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`MY_NUMBER`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// number&lt;/span&gt;

&lt;span class="c1"&gt;// Optional&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MY_BOOLEAN&lt;/span&gt; &lt;span class="o"&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;optional&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`MY_BOOLEAN`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// boolean | undefined&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MY_NUMBER&lt;/span&gt; &lt;span class="o"&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;optional&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`MY_NUMBER`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// number | undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, you might want to check whether the variable is one of the allowed values. This check always occurs after the presence/empty checks and typecasting the value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MY_NUMBER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`MY_NUMBER`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;allowedValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1202&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1378&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the &lt;a href="https://www.npmjs.com/package/safe-env-vars"&gt;docs&lt;/a&gt; for more usage information and examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended pattern
&lt;/h2&gt;

&lt;p&gt;I would recommend you have a single point of entry for the environment variables in your application. One place where you read in all the values needed by the different modules and functions. This ensures that there’s only one place to look and one place to change when making modifications.&lt;/p&gt;

&lt;p&gt;I like to structure my single point of entry in JavaScript/TypeScript projects like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/src/
    /main.ts
    /config/
        /env.ts
        /constants.ts
        /index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ./config/env.ts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;EnvironmentReader&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;safe-env-vars&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;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EnvironmentReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;COMMISSION_RATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`COMMISSION_RATE`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ./config/constants.ts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SOME_CONSTANT_VALUE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ANOTHER_CONSTANT_VALUE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Hello, World`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ./config/index.ts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./env&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;constants&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ...and the usage?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;COMMISSION_RATE&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SOME_CONSTANT_VALUE&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;calculateCommission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&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;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;COMMISSION_RATE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This results in a very clean way of working with configurable environment variables as well as constant values. The benefits of this approach are that there is a single point of entry for the environment variables in your application, and every usage of these values directs the reader back to that entry point.&lt;/p&gt;

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

&lt;p&gt;Don’t fall into the trap of believing that because you’ve been using environment variables for years that they’re safe and can’t surprise you. It’s better to trust but verify the values you’re reading using a robust and time-saving library such as &lt;a href="https://www.npmjs.com/package/safe-env-vars"&gt;safe-env-vars&lt;/a&gt;* which does the hard work for you.&lt;/p&gt;

&lt;p&gt;*Alternative options may exist. 🙃&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Engineering Principles for Unruly Artists</title>
      <dc:creator>Josh Cole</dc:creator>
      <pubDate>Wed, 30 Dec 2020 12:32:13 +0000</pubDate>
      <link>https://dev.to/saikojosh/engineering-principles-for-unruly-artists-50gb</link>
      <guid>https://dev.to/saikojosh/engineering-principles-for-unruly-artists-50gb</guid>
      <description>&lt;p&gt;Leading a team of intelligent and passionate engineers can feel too much like herding cats at times. Problem solving of any kind is a deeply creative activity, and with creativity comes mess. Lots of mess. This is particularly the case when there isn't just one artist painting on canvas, but many, with their respective paint brushes fighting to manifest their unique ideas.&lt;/p&gt;

&lt;p&gt;We all come from different backgrounds, have differing educations, and unique life experiences. These individual perspectives are built up over a lifetime and they can and should lead to healthy (and most importantly, productive) technical discussions.&lt;/p&gt;

&lt;p&gt;However, that's not always the case! I've seen teams where the conflicting viewpoints constantly trigger meaningless debates. Debates that divert the team's finite energy and brainpower from the key tasks at hand.&lt;/p&gt;

&lt;p&gt;I've seen teams where specific members have such entrenched views they can't begin to see a different way of working. They often end up going off on their own and writing code only they can work with effectively.&lt;/p&gt;

&lt;p&gt;What's the result? Paint everywhere.&lt;/p&gt;

&lt;p&gt;This crazy artistry is why we see the most effective teams being those that are well disciplined, working in lockstep. Each member playing their own unique role but in concert with everybody else.&lt;/p&gt;

&lt;p&gt;It's tempting to look at that discipline and determine that it must come from an autocratic command and control approach, with rules and orders flowing down from the top to the implementers below.&lt;/p&gt;

&lt;p&gt;This is "easy" for leadership to do, it's also incredibly lazy. Nobody has to think about integrating conflicting ideas, even if that means good ideas, better ideas, are lost. Because the "best" way, the only way, has already been dictated.&lt;/p&gt;

&lt;p&gt;The problem is, it would be impossible to write up a complete list of rules for how to engineer software. The list would be insanely long, and many of the rules would conflict with each other. Not to mention you'd need to know the context of each situation to judge whether the rules had been followed appropriately.&lt;/p&gt;

&lt;p&gt;This kind of dictatorial rule-setting ends up being counter-productive as it requires either dumb obedience or cognitive overload. Neither are desirable when cognitive energy is at such a staggering premium. Hiring more people and more expensive skill sets simply isn't the smartest move.&lt;/p&gt;

&lt;p&gt;So what's a better way to manage creative individuals?&lt;/p&gt;

&lt;h1&gt;
  
  
  Practical Principles
&lt;/h1&gt;

&lt;p&gt;A good analogy for principles are the guide rails bowling alleys provide for children and the perennially inaccurate. They don't guarantee you're going to hit a strike on your first bowl but they do ensure the resulting output is within an acceptable range.&lt;/p&gt;

&lt;p&gt;Successful entrepreneur Elon Musk and others talk about reasoning from first principles in order to solve problems more effectively. Why should software engineering be any different?&lt;/p&gt;

&lt;p&gt;Instilling a set of principles in a team allows for much faster implementation and iteration. There's just no need to think about &lt;em&gt;how&lt;/em&gt; to architect solutions or to confirm every decision with a superior, because an acceptable range of "hows" has already been defined.&lt;/p&gt;

&lt;p&gt;Anything that reduces cognitive load and opens up more mental capacity for solving problems is a winner in my book. The trick is for the principles to leave sufficient scope for innovation, personal flair, and team input, without being so loose as to be useless.&lt;/p&gt;

&lt;p&gt;The principles I personally like to follow err towards maintainability and practicality. I have a bias for getting stuff done rather than indulging in an academic sense of correctness, because for me, it's more important to have a mostly correct but useful output, than a perfectly correct pipedream.&lt;/p&gt;

&lt;p&gt;That probably comes from a background in innovation rather than engineering. A different perspective for sure. Now of course this won't be appropriate for all situations so please modify as appropriate!&lt;/p&gt;

&lt;h1&gt;
  
  
  My Principles
&lt;/h1&gt;

&lt;p&gt;This list is my current best effort as of December 2020 and I fully expect it to change over time as I learn new things. The principles below are in ascending order and build upon each other.&lt;/p&gt;

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

&lt;p&gt;Generally said, it's better to favour simple solutions over complex ones. Sometimes the overarching solution may be inescapably complex, but the constituent parts of that solution can still be kept simple themselves.&lt;/p&gt;

&lt;p&gt;Simplicity is good for many reasons, not least because we're only human and we will all make mistakes. In short, &lt;em&gt;simple&lt;/em&gt; means easy to understand... easy to understand means safe to change... safe to change means a low risk for introducing bugs... and so on.&lt;/p&gt;

&lt;p&gt;Typically I'd consider a concept to be simple if a developer can hold the entire working knowledge of it in their head at one time. Obviously this doesn't apply to entire software systems, but rather to each individual part.&lt;/p&gt;

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

&lt;p&gt;It's no good just choosing simplicity over complexity. The way code is written and the way problems are solved should also be broadly consistent across a codebase. Having 500 unique approaches might yield marginal innovation in some areas, but it's painful, time consuming, and costly to maintain such unlimited variety.&lt;/p&gt;

&lt;p&gt;Consistency also applies to conforming to the generally accepted way of doing things both inside and outside your current team and organisation. That's because developers coming from elsewhere will probably expect things to work a certain way.&lt;/p&gt;

&lt;p&gt;We have international standards for a reason, the same reason that we tell developers "don't repeat yourself" and consider "code reusability". Doing things differently and reinventing the wheel for no good reason introduces cognitive overhead. And bugs sure love to take advantage of overloaded developers.&lt;/p&gt;

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

&lt;p&gt;Simple and consistent code lends itself nicely to legibility - the quality of being clear to read and easy to digest. Maybe you can impress yourself with the shortest possible piece of code. Great. Pat on the back. Now give that to someone else after you're long gone, or even your future self next year, and hope they can figure it out in a sensible amount of time.&lt;/p&gt;

&lt;p&gt;Whether it's showing off or laziness, short code is a pain to unpick. It's a pain to review. It's a pain to modify. A bit more verbosity to make your intentions clear goes a long way to explaining your thought process to other developers.&lt;/p&gt;

&lt;p&gt;Engineering is a team sport that requires constant communication through code, and as with any form of communication you can't expect others to magically devine what's going on inside your head. Make it explicit. As in life it's better to over-communicate than to under-communicate.&lt;/p&gt;

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

&lt;p&gt;In all likelihood, code that is simple, consistent, and legible, probably only does one thing. That's because code that only has one responsibility is much easier to reason about. It's easier to understand how the internals work and how it fits into the larger picture as a whole.&lt;/p&gt;

&lt;p&gt;Singular responsibility is a sturdy design principle that applies at all levels. From the application as a whole, to each microservice, class, function, variable, all the way down to individual lines of code. Everything benefits from having a clear, singular purpose.&lt;/p&gt;

&lt;p&gt;It also makes it infinitely easier to reuse code in multiple places when that code only does one thing, but does it well. It becomes possible to stitch together (compose) units of code in multiple different ways to produce multiple different outcomes. A core tenet of functional programming.&lt;/p&gt;

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

&lt;p&gt;Code that is simple, consistent, legible, and has a singular responsibility, provides an amazing foundation for predictability. Now we're really getting to the crux of the matter, because for me, predictability is the holy grail of building reliable, bug-free software.&lt;/p&gt;

&lt;p&gt;Often our software can seem like a wild beast. We release it into the wilderness* (*also called production) with what we think is a good understanding of how it will behave, only to find that when our wild beast meets reality its behaviour is anything but rational.&lt;/p&gt;

&lt;p&gt;Of course we use automated testing, code quality checks, partial roll-outs, automated rollbacks, code reviews, and a whole host of other techniques to assess the behaviour of our code. And these things are absolutely necessary in an imperfect world.&lt;/p&gt;

&lt;p&gt;But we could have made our lives a whole lot easier if only we had started with code that's predictable in the first place. That means following all of the above principles as well as more concrete techniques such as minimising side effects, avoiding shared state, and so on.&lt;/p&gt;

&lt;p&gt;If we can predict how our code is going to behave before we release it into the wild we'll be able to pre-empt and correct much more of its undesired behaviour before it impacts users.&lt;/p&gt;

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

&lt;p&gt;Hopefully by now you get how this works. Code that is simple, consistent, legible, with a singular responsibility, and is predictable, has the potential to be considerably more reliable.&lt;/p&gt;

&lt;p&gt;Reliability refers to two things here; firstly that the software conforms to whatever specifications have been set out, whether that comes from internal stakeholders or from the customer(s) themselves.&lt;/p&gt;

&lt;p&gt;This is important because we need to know what the software &lt;em&gt;should&lt;/em&gt; be doing even if that's at a high level (we don't want to be doing waterfall here). As discussed above we can use automated testing and associated techniques to assess this.&lt;/p&gt;

&lt;p&gt;Secondly, reliability refers to the software behaving as expected when end-users get their hands on it out in the wild (AKA production). Now I'm not saying that it should be perfectly bug free. A known bug that reliably results in the same behaviour every time it occurs may be a nuisance but it's a manageable nuisance.&lt;/p&gt;

&lt;p&gt;Reliable software is software that consistently behaves in the same way every time (that also includes being "up" and available when a user needs to access it, in case you're asking). The key here is consistent behaviour, users will be able to work around limitations and bugs, and as a team you'll be able to fix them that much easier.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;So there you have it. For software to be &lt;strong&gt;reliable&lt;/strong&gt; it must first be &lt;strong&gt;predictable&lt;/strong&gt;, which requires that each part has a single &lt;strong&gt;responsibility&lt;/strong&gt;, that the code is &lt;strong&gt;legible&lt;/strong&gt;, and that problems are solved in a &lt;strong&gt;consistent&lt;/strong&gt; way, recognising that &lt;strong&gt;simple&lt;/strong&gt; solutions are usually better than complex ones.&lt;/p&gt;

&lt;p&gt;These are the six principles by which I guide my teams to design and build high quality software. It may be an ever evolving set of principles but it's a set that's carried me a fair distance so far, and I hope with a bit more tweaking, much further into the future.&lt;/p&gt;

&lt;p&gt;Comments, war stories, and differing opinions are welcomed! :) &lt;/p&gt;

</description>
      <category>leadership</category>
      <category>healthydebate</category>
      <category>productivity</category>
      <category>management</category>
    </item>
    <item>
      <title>5 VS Code Extensions For Team Productivity</title>
      <dc:creator>Josh Cole</dc:creator>
      <pubDate>Tue, 17 Nov 2020 20:23:51 +0000</pubDate>
      <link>https://dev.to/saikojosh/5-vs-code-extensions-for-team-productivity-39g</link>
      <guid>https://dev.to/saikojosh/5-vs-code-extensions-for-team-productivity-39g</guid>
      <description>&lt;p&gt;Is your team as productive as it could be? Maybe it's close, although I'd put money on there being room for improvement in there somewhere.&lt;/p&gt;

&lt;p&gt;Now, IDE extensions aren't going to solve major problems by any stretch of the imagination, but they will help you eek out that little bit more productivity without asking anything more of the team.&lt;/p&gt;

&lt;p&gt;And that's what productivity is often about; lots of small tweaks and adjustments that allow humans to do what they do best (craftsmanship and creative work) by leveraging better tools.&lt;/p&gt;

&lt;p&gt;As Confucius said;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If a craftsman wants to do good work, he must first sharpen his tools."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The following are five VS Code extensions that I encourage every engineer on my team to utilise. Each of them has a small but valuable incremental contribution to productivity, hence the recommendation.&lt;/p&gt;

&lt;h1&gt;
  
  
  5 - &lt;a href="https://marketplace.visualstudio.com/items?itemName=gruntfuggly.todo-tree"&gt;Todo Tree&lt;/a&gt;
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;Todo Tree quickly searches your workspace for comment tags like &lt;code&gt;TODO&lt;/code&gt;, &lt;code&gt;HACK&lt;/code&gt;, and &lt;code&gt;FIXME&lt;/code&gt;, displaying them in a tree view in the sidebar.&lt;/p&gt;

&lt;p&gt;Clicking a TODO within the tree will open the file and navigate to the correct line, whilst the comments themselves will be highlighted so they're visually annoying and less likely to get missed. This can be configured in settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TtmNhR58--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/j6wik9v3v9ipvjgsgqcs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TtmNhR58--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/j6wik9v3v9ipvjgsgqcs.png" alt="Todo Tree" width="880" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why
&lt;/h3&gt;

&lt;p&gt;I generally don't like to see "todo" comments like this left in code, particularly code that's supposedly "finished" and/or going into production.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TODO: implement new feature&lt;/span&gt;
&lt;span class="c1"&gt;// FIXME: this is a known issue I haven't fixed yet&lt;/span&gt;
&lt;span class="c1"&gt;// HACK: revisit this later when we have more time&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That being said, life is messy and it's not always possible to avoid such things. Developers are bound to write these  comments and they sometimes get accidentally committed to source control, it happens. 🤷‍♂️&lt;/p&gt;

&lt;p&gt;And there are times when the comments have actual value such as when pushing code at the end of the workday to act as reminders for tomorrow, or if a developer is off sick and someone else needs to pick up where they left off.&lt;/p&gt;

&lt;p&gt;I don't tend to encourage these comments, but given the fact they will crop up somewhere we might as well have a good tool for finding and dealing with them. This is especially useful when code is changing quickly in the early stages of a new project.&lt;/p&gt;
&lt;h1&gt;
  
  
  4 - &lt;a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens"&gt;GitLens&lt;/a&gt;
&lt;/h1&gt;
&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;GitLens provides a more visually friendly UI to work with Git repositories with shortcuts for many common uses of the tool.&lt;/p&gt;

&lt;p&gt;It helps with visualising code authorship through surfacing useful information directly in the code editor, and via tools for git blame, history navigation, and code comparisons.&lt;/p&gt;

&lt;p&gt;The extension also comes with lots of customisation options to adjust its behaviour to your individual tastes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SgVVyYG---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/90ynb57rbbsw3zobupja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SgVVyYG---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/90ynb57rbbsw3zobupja.png" alt="GitLens" width="610" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KyLC8XWr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c6se3jnndpzxeepnkqtu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KyLC8XWr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c6se3jnndpzxeepnkqtu.png" alt="GitLens" width="610" height="216"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Why
&lt;/h3&gt;

&lt;p&gt;I've used Git for every project for many years as I suspect you have too. Git is a complex tool to master fully and engineers in your team will be at different stages in their learning.&lt;/p&gt;

&lt;p&gt;That's where this extension comes in. Simplification of a complex tool is a valuable endeavour. This extension also means developers don't have to switch context between their IDE, the command line and your VCS provider.&lt;/p&gt;

&lt;p&gt;Since Microsoft's purchase of GitHub the Git integration in VS Code has come on leaps and bounds. Perhaps in the future this extension won't be necessary at all.&lt;/p&gt;

&lt;p&gt;For now, GitLens enables some valuable insights into the evolution of your codebase without needing to resort to the command line or the online tools of your VCS.&lt;/p&gt;
&lt;h1&gt;
  
  
  3 - &lt;a href="https://marketplace.visualstudio.com/items?itemName=editorconfig.editorconfig"&gt;Editorconfig&lt;/a&gt;
&lt;/h1&gt;
&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs.&lt;/p&gt;

&lt;p&gt;This extension reads the &lt;code&gt;.editorconfig&lt;/code&gt; committed to your project's repository and automatically applies the settings within when you switch to the project. Full definition of the options available can be found here: &lt;a href="https://editorconfig.org"&gt;https://editorconfig.org&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;For me, consistency is an important principle of high quality engineering. Consistency reduces mistakes because it reduces the cognitive load on those reading or writing the code, and it quickly becomes implicitly understood how something should or could work without needing to deep dive every time a similar problem crops up.&lt;/p&gt;

&lt;p&gt;Editor Config has been around for quite some time and it's one of those very simple tools that ensures a modicum of consistency between developers. I like to keep git diffs as clean as possible, and seeing changes to things like trailing whitespace, newlines, indentation characters, and so on quickly becomes painful.&lt;/p&gt;

&lt;p&gt;The extension automatically sets the correct IDE settings for each project you switch into based on an &lt;code&gt;.editorconfig&lt;/code&gt; file in the repository root.&lt;/p&gt;

&lt;p&gt;Make a decision on the style to follow and be done with it. All developers with this extension installed will then be writing code in the same style, keeping git diffs clear of whitespace noise.&lt;/p&gt;
&lt;h1&gt;
  
  
  2 - &lt;a href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker"&gt;Code Spell Checker&lt;/a&gt;
&lt;/h1&gt;
&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;Code Spell Checker is a basic spell checker that works well with camelCase code. The goal of the extension is to catch common spelling errors whilst keeping the number of false positives low.&lt;/p&gt;

&lt;p&gt;It's not designed to be as comprehensive as a word processor spell checker but it does well enough to prevent silly mistakes.&lt;/p&gt;

&lt;p&gt;The extension also supports many more languages than US English which is a boon for those of us who work in other variants of English or entirely different languages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pliTT-AK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s2mx6jbtink8w3sq3ksq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pliTT-AK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s2mx6jbtink8w3sq3ksq.gif" alt="Code Spell Checker" width="745" height="539"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Why
&lt;/h3&gt;

&lt;p&gt;Spelling mistakes are common. That might not be a dealbreaker for passive code such as comments, documentation, strings containing user notifications, and so on, but it can have a huge knock-on effect and mistakes tend to live forever.&lt;/p&gt;

&lt;p&gt;See the case of the HTTP Referrer header that was &lt;a href="https://en.wikipedia.org/wiki/HTTP_referer"&gt;misspelled&lt;/a&gt; in the original specification over 20 years ago and continues to live on forever more.&lt;/p&gt;


&lt;div class="ltag__wikipedia--container"&gt;
  &lt;div class="ltag__wikipedia--header"&gt;
    &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Sew3uq9H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/wikipedia-logo-0a3e76624c7b1c3ccdeb9493ea4add6ef5bd82d7e88d102d5ddfd7c981efa2e7.svg" class="ltag__wikipedia--logo" alt="Wikipedia Logo" width="128" height="128"&gt;
    &lt;a href="https://en.wikipedia.org/wiki/HTTP_referer#Etymology" rel="noopener noreferrer"&gt;HTTP referer - Etymology&lt;/a&gt;
  &lt;/div&gt;
  &lt;div class="ltag__wikipedia--extract"&gt;

&lt;p&gt;The misspelling of &lt;i&gt;referrer&lt;/i&gt; was introduced in the original proposal by computer scientist Phillip Hallam-Baker to incorporate the &lt;span&gt;"Referer"&lt;/span&gt; header field into the HTTP specification.&lt;span class="mw-ref reference" id="cite_ref-hallam-baker_7-0"&gt;&amp;lt;span class="mw-reflink-text"&amp;gt;[7]&amp;lt;/span&amp;gt;&lt;/span&gt; The misspelling was set in stone by the time (May 1996) of its incorporation into the Request for Comments standards document RFC 1945&lt;span class="mw-ref reference" id="cite_ref-rfc1945_8-0"&gt;&amp;lt;span class="mw-reflink-text"&amp;gt;[8]&amp;lt;/span&amp;gt;&lt;/span&gt; (which 'reflects common usage of the protocol referred to as "HTTP/1.0"' at that time); document co-author Roy Fielding remarked in March 1995 that "neither one (&lt;span&gt;referer&lt;/span&gt; or referrer) is understood by" the standard Unix spell checker of the period.&lt;span class="mw-ref reference" id="cite_ref-fielding_9-0"&gt;&amp;lt;span class="mw-reflink-text"&amp;gt;[9]&amp;lt;/span&amp;gt;&lt;/span&gt; &lt;span&gt;"Referer"&lt;/span&gt; has since become a widely used spelling in the industry when discussing HTTP referrers; usage of the misspelling is not universal, though, as the correct spelling "referrer" is used in some web specifications such as the &amp;lt;code&amp;gt;Referrer-Policy&amp;lt;/code&amp;gt; HTTP header or the Document Object Model.&lt;span class="mw-ref reference" id="cite_ref-Leak_3-1"&gt;&amp;lt;span class="mw-reflink-text"&amp;gt;[3]&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;/p&gt;


&lt;/div&gt;


&lt;div class="ltag__wikipedia--btn--container"&gt;
&lt;br&gt;
    &lt;br&gt;
      &lt;a href="https://en.wikipedia.org/wiki/HTTP_referer#Etymology" rel="noopener noreferrer"&gt;View on Wikipedia&lt;/a&gt;&lt;br&gt;
    &lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Incorrectly named functions, variables and so on tend to be hard to change once baked in, and may cause confusion and frustration for every developer that ever needs to read or use that code in the future.&lt;/p&gt;

&lt;p&gt;Mistakes like this tend to take more energy to correct than you might want to expend. So save yourself the eternal embarrassment and get it right first time.&lt;/p&gt;

&lt;h1&gt;
  
  
  1 - &lt;a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode"&gt;Prettier&lt;/a&gt;
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;Prettier is an opinionated code formatter. It enforces a consistent style by parsing your code and re-printing it with its own rules that take the maximum line length into account, wrapping code when necessary.&lt;/p&gt;

&lt;p&gt;Prettier supports: JavaScript, TypeScript, Flow, JSX, JSON, CSS, SCSS, Less, HTML, Vue, Angular, GraphQL, Markdown, and YAML. Full definition of the options available can be found here: &lt;a href="https://prettier.io"&gt;https://prettier.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gzl6iuwW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2ov4xbm762ep2bc76kls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gzl6iuwW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2ov4xbm762ep2bc76kls.png" alt="Prettier" width="880" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why
&lt;/h3&gt;

&lt;p&gt;Now I know not all engineers will be writing code in languages that Prettier supports, but for those developers who are it's a huge timesaver. Similar to the Editor Config extension above, Prettier automates work that is valuable but quickly becomes a huge time sink such as formatting and organising code to make it consistent and readable.&lt;/p&gt;

&lt;p&gt;Prettier is useful for the languages it supports because those languages are so flexible they can be written in many styles. Not to mention that most of them don't have official style guides or formatting tools, unlike more modern languages.&lt;/p&gt;

&lt;p&gt;I can't count how many hours I've seen wasted by developers arguing over whether semicolons are necessary in JavaScript, or whether indentation should be tabs or spaces, or reading git diffs that are mired with stylistic changes.&lt;/p&gt;

&lt;p&gt;Whilst there are sensible answers to all these crinkles, I've seen these debates continue to rage unnecessarily in every team. Prettier puts an end to all that by enforcing an opinionated style on all developers with only a small amount of flexibility to change its behaviour.&lt;/p&gt;

&lt;p&gt;What I love about Prettier is that code styling is applied automatically on save so I don't need to even think about how tidy I'm being, Prettier does that for me. Plus one for productivity!&lt;/p&gt;




&lt;p&gt;🌍 &lt;a href="https://www.joshuacole.me"&gt;Website&lt;/a&gt; | 📇 &lt;a href="https://www.linkedin.com/in/joshcoleuk"&gt;LinkedIn&lt;/a&gt; | 🐥 &lt;a href="https://www.twitter.com/saikojosh"&gt;Twitter&lt;/a&gt; | 📕 &lt;a href="https://dev.to/saikojosh"&gt;Dev.to&lt;/a&gt; | 📗 &lt;a href="https://www.medium.com/@saikojosh"&gt;Medium&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>leadership</category>
      <category>productivity</category>
      <category>management</category>
    </item>
  </channel>
</rss>
