<?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: Vsevolod Rodionov</title>
    <description>The latest articles on DEV Community by Vsevolod Rodionov (@jabher).</description>
    <link>https://dev.to/jabher</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%2F69400%2F2a1e76f2-b5b0-4a99-bd0e-8bcf8403c691.jpeg</url>
      <title>DEV Community: Vsevolod Rodionov</title>
      <link>https://dev.to/jabher</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jabher"/>
    <language>en</language>
    <item>
      <title>Running next.js in cluster mode (dead simple)</title>
      <dc:creator>Vsevolod Rodionov</dc:creator>
      <pubDate>Wed, 17 Aug 2022 13:06:00 +0000</pubDate>
      <link>https://dev.to/jabher/running-nextjs-in-cluster-mode-dead-simple-2f72</link>
      <guid>https://dev.to/jabher/running-nextjs-in-cluster-mode-dead-simple-2f72</guid>
      <description>&lt;p&gt;Honestly, I feel like an idiot - I've been maintaining Next.js apps last few years, and thought Next.js is automatically running clustered in production.&lt;/p&gt;

&lt;p&gt;Moreover, I did not find any nice solutions for running Next.js clusterized - everything is over-complicated with ton of code.&lt;/p&gt;

&lt;p&gt;Well, turned out (at least for Next 12) it is really simple - and Google did not give me any nice answer, so I had to research on it by myself today.&lt;/p&gt;

&lt;p&gt;So, here's the solution - mostly simply based on node &lt;code&gt;cluster&lt;/code&gt; docs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:cluster&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;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:process&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;cpus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:os&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;numCPUs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cpus&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isPrimary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Primary &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;pid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is running`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// all the magic goes here. &lt;/span&gt;
  &lt;span class="c1"&gt;// `setupPrimary` is altering cluster behaviour&lt;/span&gt;
  &lt;span class="c1"&gt;// see docs: https://nodejs.org/api/cluster.html#clustersetupprimarysettings&lt;/span&gt;
  &lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setupPrimary&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// node_modules/.bin is directory for all runtime scripts,&lt;/span&gt;
    &lt;span class="c1"&gt;// including `next`.&lt;/span&gt;
    &lt;span class="c1"&gt;// we can work with it like with a common node package,&lt;/span&gt;
    &lt;span class="c1"&gt;// so require.resolve simply gives us path for `next` CLI &lt;/span&gt;
    &lt;span class="na"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.bin/next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;// args should skip first 2 arguments, &lt;/span&gt;
    &lt;span class="c1"&gt;// "node" path and file to execute path&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
    &lt;span class="c1"&gt;// just directly passing all the IO to not handle pipes&lt;/span&gt;
    &lt;span class="na"&gt;stdio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inherit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// making stdout and stderr colored&lt;/span&gt;
    &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;numCPUs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;exit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`worker &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;worker&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;pid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; died`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// we do not need to do "else" here as cluster will run different file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>nextjs</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What are template strings really for?</title>
      <dc:creator>Vsevolod Rodionov</dc:creator>
      <pubDate>Wed, 09 Sep 2020 20:40:46 +0000</pubDate>
      <link>https://dev.to/jabher/what-are-template-strings-really-for-3p6l</link>
      <guid>https://dev.to/jabher/what-are-template-strings-really-for-3p6l</guid>
      <description>&lt;p&gt;Since template strings (aka &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals"&gt;template literals&lt;/a&gt;) were released I was feeling that they were kind of unappreciated. &lt;/p&gt;

&lt;p&gt;No, of course everyone loved an ability to write like &lt;code&gt;hello${world}&lt;/code&gt;, and tricks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;escape&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;html/&amp;gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;worked great, but for years I was sure they can do more.&lt;/p&gt;

&lt;p&gt;I love one not-so-well-known NoSQL graph database - &lt;a href="https://neo4j.com/"&gt;Neo4j&lt;/a&gt;, and I've been building projects with it occasionally.&lt;/p&gt;

&lt;p&gt;It was nice, but query syntax was not so great, so I had to write like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MERGE (alice:Person {name : $nameParam, age : $ageParam})&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;nameParam&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ageParam&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and I was literally struggling to think out the name for each variable. &lt;/p&gt;

&lt;p&gt;For more context: this is complex query database for research with ton of capabilities and no schema, you cannot simply create an ORM for it, so I had to write raw queries. Simple example of todo list query: &lt;em&gt;"do this task has dependent tasks of infinite deep that are blocked not by other dependencies of this task?"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So, turned out template strings can actually solve this problem and make this simple as hell. I've created a lib for this - &lt;a href="https://www.npmjs.com/package/cypher-talker"&gt;cypher-talker&lt;/a&gt; and now I'm writing like this, feeling myself really happy for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="s2"&gt;`MERGE (alice:Person {name : &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, age : &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I'm planning to simplify it more and write a monkey-patch to write like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="s2"&gt;`MERGE (alice:Person {name : &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, age : &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;but it requires some other driver extensions - like transactions Realms wrapper, but I'll write on it when I'm done with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, what is the trick?
&lt;/h2&gt;

&lt;p&gt;Template strings are expected to be a &lt;strong&gt;pure functions&lt;/strong&gt;. This is important: you are generally not intended to alter something in it. You can, but generally even ESLint will stop you - &lt;a href="https://eslint.org/docs/rules/no-unused-expressions"&gt;no-unused-expressions&lt;/a&gt; rule prevents you from doing it by default.&lt;/p&gt;

&lt;p&gt;Template literal (yes, that's how function to use with template strings called) should have a following signature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;literals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TemplateStringsArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What is cool: typescript fully understands signature of template function, so it will detect an error here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;literals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TemplateStringsArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;

&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="s2"&gt;`hello&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;

&lt;span class="c1"&gt;// and even here!&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;literals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TemplateStringsArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;string&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="p"&gt;...&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;

&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="s2"&gt;`hello&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&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="s2"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With typescript 4 and its advanced tuples it now works amazing!&lt;/p&gt;

&lt;p&gt;If you're curious, what &lt;code&gt;TemplateStringsArray&lt;/code&gt; is - it is simply &lt;code&gt;ReadonlyArray&amp;lt;string&amp;gt;&lt;/code&gt;, nothing special.&lt;/p&gt;

&lt;p&gt;Note that literals size is always 1 time bigger than placeholders length. It will always has a string - even empty, so its reduction may be a bit complicated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Second magic is that it can return anything
&lt;/h2&gt;

&lt;p&gt;For my lib I needed to produce something spreadable - I mean, iterable. You can return anything: object, array, WeakRef or function. It will simply work.&lt;/p&gt;

&lt;p&gt;I know, this looks obvious, but when you really understand what that does mean - you will see a world of possibilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Imagine NestJS, but with template string decorators
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="s2"&gt;`docs`&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Redirect&lt;/span&gt;&lt;span class="s2"&gt;`https://docs.nestjs.com`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;getDocs&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Query&lt;/span&gt;&lt;span class="s2"&gt;`version`&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://docs.nestjs.com/v5/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I think, it looks amazing. Simply remove brackets - and now it looks really declarative. It starts to look not like bunch of function calls all around, but like a some kind of DSL, really.&lt;/p&gt;

&lt;p&gt;If you forget how it looks like right now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;docs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://docs.nestjs.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;getDocs&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://docs.nestjs.com/v5/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Or imagine tests, but with decorator fns
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="s2"&gt;`tests error with async/await and rejects`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assertions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUserName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;rejects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User with 3 not found.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Looks simple, but what if we will drop some parametrized testing in it?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`should return true for prime number &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isPrime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;//vs&lt;/span&gt;

&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`should return true for prime number &lt;/span&gt;&lt;span class="p"&gt;${[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isPrime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;note: yes, I know that DoneCallback usually should be there, but I'm speaking on general concept, not specific framework&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you think it is not possible with types: it works on nightly TS 4.1. There is issues right now with recursive conditional types in latest TS, but they are fixing it. &lt;a href="https://www.typescriptlang.org/play?ts=4.1.0-insiders.20200909#code/C4TwDgpgBAxghgJwDwBUB8UC8UVQgD2AgDsATAZygG0BLYgMwgSgCUAaKAOm7mJCoC6AqAH5WUAFxRiEAG5MAUKEixSydFhx5CJCtV4gO3TnUbMWwsS0nUBCpeGhgaMANYpHqDNlwEiZSgBBBAQ4ECRTJlYMKxsZeQR7ZScXVwAxGgRyYFRtfz0qYwBXYldiAHsAd2JBQQFvLT9dSkFRWxsqZzcPSCR4dTQ0I24u9MzsvrUvNDsFGHLibKgaYE1cpoDqYtKK6tqhNAAKABsVpjhj8ikUCABbMGO4IgBlYAQ6AHNyYNDDLhHHjAIAALcrHUhMK44ACUWAwAG8FFBkVAEBBgEUEMQoId6MQpIdjIgvlJRhksjl0LDMBhZOUaKRqQj7CioABfBQchQrAAGwIgx2O5QAJPCqABySrlBDg8UCNlQUVUN5FCAcACs8p5h0Osik2XexA+HA+UmIRVuACMogAfKCW8pgiC8JlQRGc6FAA"&gt;TS playground&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// a bit of functional magic&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;car&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;cdr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;pickType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;pickFirst&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[][]]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; 
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; 
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;pickType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;car&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pickFirst&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;cdr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[][]]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;literals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TemplateStringsArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pickFirst&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="s2"&gt;`hello&lt;/span&gt;&lt;span class="p"&gt;${[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${[&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="c1"&gt;// test it!&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I really think that template strings are damn unappreciated. They can bring you DSL you want - and keep the glory of types.&lt;/p&gt;

&lt;p&gt;Try to love them more!&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>I decided to create my own Node.js router/http-server, performance and devops-aimed. What should I consider?</title>
      <dc:creator>Vsevolod Rodionov</dc:creator>
      <pubDate>Sun, 26 Apr 2020 16:16:26 +0000</pubDate>
      <link>https://dev.to/jabher/i-decided-to-create-my-own-node-js-router-http-server-performance-and-devops-aimed-what-should-i-consider-472o</link>
      <guid>https://dev.to/jabher/i-decided-to-create-my-own-node-js-router-http-server-performance-and-devops-aimed-what-should-i-consider-472o</guid>
      <description>&lt;p&gt;I decided to create yet another "express-killer" (work already in progress) pet project.&lt;br&gt;
Of course, not NIH syndrome: I'm going to make it Express middleware-compatible.&lt;br&gt;
Target is to make it fast as hell in its core and modern tooling integration-aimed without losing friendliness and already known experience.&lt;br&gt;
What should I consider?&lt;/p&gt;

&lt;p&gt;What I already keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;blazing-fast generic router package, which can be mounted over both Koa and Express. Better than common trie solutions - I've inspected popular ones and I know parts of code that can be done in a more efficient way by adding the "compile" step. I'm also going to try WASM router implementation, but unsure whether interop will degrade the performance. Routes will be &lt;a href="https://github.com/pillarjs/path-to-regexp"&gt;path-to-regexp&lt;/a&gt;-compatible (like Express), with the ability to define regex paths with the lowest priority order.&lt;/li&gt;
&lt;li&gt;separation of endpoints and middlewares, while keeping in mind that endpoints can end the request (like "if not authorized, redirect to home"), and integration with documentation extractors like Swagger (or any other generic solution).&lt;/li&gt;
&lt;li&gt;simple integration possibility with modern APMs like New Relic, Prometheus, and other popular ones. Not full integration at the first step, but the ability to extract nice metrics (like per-path) in the core.&lt;/li&gt;
&lt;li&gt;built-in &lt;code&gt;forever&lt;/code&gt; or other Cluster and auto-reload package; also, support of &lt;a href="https://github.com/indutny/sticky-session"&gt;sticky-session&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;СSP declarative configuration and tracing ID out-of-the-box (middleware call-style, but working differently inside)&lt;/li&gt;
&lt;li&gt;profiling-friendly - middlewares will be not in a stack, instead, they will have a flat call structure and this will allow a profiler to show separate calls instead of call stacks.&lt;/li&gt;
&lt;li&gt;some kind of Dependency Injection solution - still thinking on it, not a lot of ideas, however.&lt;/li&gt;
&lt;li&gt;Node 14-tuned - if something is improving performance on 14, but breaks or degrades 10 or 12, this is good. Not expecting to release before 14 go to LTS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just to clear things out - I'm team-/tech-lead/architect working on frontends and backends-for-frontends in large scale projects (~10k pages per second served on a current one) with 8+ years of experience, this is not a newbie post - I'm really struggling to hear pains in modern solutions.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>devops</category>
      <category>discuss</category>
      <category>node</category>
    </item>
    <item>
      <title>State vs knowledge: you should make your apps a bit more complex to keep them simple</title>
      <dc:creator>Vsevolod Rodionov</dc:creator>
      <pubDate>Tue, 17 Mar 2020 15:49:11 +0000</pubDate>
      <link>https://dev.to/jabher/state-vs-knowledge-40d</link>
      <guid>https://dev.to/jabher/state-vs-knowledge-40d</guid>
      <description>&lt;p&gt;Generally, every client web app - SPA, PWA, whatever - real soul is state.&lt;/p&gt;

&lt;p&gt;We may brag on React, Vue or Svelte, we may shamefully (or proudly) continue to use jQuery, but what really defines the way we think, the way we tighten up with back-end, APIs and storage? State and the way you manage it.&lt;/p&gt;

&lt;p&gt;And ton of people are struggling from state manager fatigue. Redux? &lt;a href="https://www.reddit.com/r/reactjs/comments/ce95u0/am_i_the_only_one_who_feels_redux_is_very/"&gt;Yes&lt;/a&gt;, &lt;a href="https://dev.to/bettercodingacademy/redux-is-seriously-overrated-change-my-mind-45pm"&gt;yes&lt;/a&gt; and &lt;a href="https://www.quora.com/Why-is-Redux-confusing"&gt;yes&lt;/a&gt;. RxJS? &lt;a href="https://www.quora.com/What-makes-RxJS-so-difficult"&gt;Sure&lt;/a&gt;. MobX? Why would it have &lt;a href="https://mobx.js.org/best/pitfalls.html"&gt;pitfalls.html&lt;/a&gt; page in docs if it simple?&lt;/p&gt;

&lt;p&gt;I think there is a solution, but first we have to fully draw the problem. &lt;/p&gt;

&lt;p&gt;When choosing the state manager, you are choosing the way you think. There is a lot of choices nowadays. Most popular are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flux/Redux-style&lt;/strong&gt; state, a global store with actions &amp;amp; reducers - well, tons of them. I would personally note &lt;a href="https://redux.js.org/"&gt;Redux&lt;/a&gt; itself, &lt;a href="https://github.com/zerobias/effector"&gt;Effector&lt;/a&gt;, &lt;a href="https://github.com/storeon/storeon"&gt;Storeon&lt;/a&gt;, &lt;a href="https://github.com/jamiebuilds/unstated"&gt;Unstated&lt;/a&gt;, and &lt;a href="https://github.com/artalar/reatom"&gt;Reatom&lt;/a&gt;. This is not "best of" list. It is about different ways on how it can look like. Also, each of them has something very unique (from my point of view), so all of them are worth giving a glance - just to check out various concepts, not to use in production!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach can be defined as &lt;strong&gt;imperative&lt;/strong&gt;/Turing-complete &amp;amp; &lt;strong&gt;global&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Observables&lt;/strong&gt; &amp;amp; &lt;strong&gt;pipes&lt;/strong&gt;. Most well-known ones are &lt;a href="https://rxjs.dev/"&gt;RxJS&lt;/a&gt; and &lt;a href="https://mobx.js.org/"&gt;MobX&lt;/a&gt;. Less known - &lt;a href="https://kefirjs.github.io/kefir/"&gt;Kefir&lt;/a&gt;, &lt;a href="https://baconjs.github.io/"&gt;Bacon&lt;/a&gt;, &lt;a href="https://cycle.js.org/"&gt;CycleJS&lt;/a&gt;. &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; goes here too. They differ a lot, but it comes from one core difference - RxJS allows &lt;a href="https://en.wikipedia.org/wiki/Strange_loop"&gt;"strange loops"&lt;/a&gt;, when you can pipe observables through observables, and MobX just creates "reactive" boxes over the variables and computations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It may sound weird, but they are aiming to be &lt;strong&gt;local/ad-hoc&lt;/strong&gt; &amp;amp; &lt;strong&gt;declarative&lt;/strong&gt;, yet still Turing-complete (I will write an article about that one day). They allow you to describe how data will be transformed, not what exactly to do with it. On some level of, um, enlightment, RxJS developers starts to avoid writing functions as much as possible, preferring to use libraries like &lt;a href="https://lodash.com"&gt;Lodash&lt;/a&gt;, or &lt;a href="https://ramdajs.com/"&gt;Ramda&lt;/a&gt;, or &lt;a href="https://github.com/gcanti/io-ts"&gt;io-ts&lt;/a&gt;, and their code actually starts tasting LISPy and looking like JSON or YAML, not real code.&lt;/p&gt;

&lt;p&gt;Speaking on local, I mean that you may have component-level observable, or application-level, or you can pass observable as an argument - you can do whatever you want with any of data sources.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GraphQL&lt;/strong&gt;-alike. &lt;a href="https://www.apollographql.com/"&gt;Apollo&lt;/a&gt; and &lt;a href="https://relay.dev/"&gt;Relay&lt;/a&gt; are best of examples, but you can find ton of them. Special mentions goes to &lt;a href="https://netflix.github.io/falcor/"&gt;Falcor&lt;/a&gt; (Netflix alternative to GraphQL query language), &lt;a href="https://gun.eco/"&gt;GunDB&lt;/a&gt; and &lt;a href="https://pouchdb.com/"&gt;PouchDB&lt;/a&gt;. Moreover, there are implementations &amp;amp; integrations with Redux, MobX, RxJS - any of them. But actual store does not matter; what really matters is the way to state the expectations. It is 100% declarative - in comparison to Flux-way imperative data reducement. And it is global.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we have 2 dimensions of state management. One is local/global, second - declaration/imperative orders. And that makes us to ask the questions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;imperative&lt;/th&gt;
&lt;th&gt;declatative&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GLOBAL&lt;/td&gt;
&lt;td&gt;Flux&lt;/td&gt;
&lt;td&gt;GraphQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LOCAL&lt;/td&gt;
&lt;td&gt;Observables&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;?????&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I should probably make a note here. Terms &lt;strong&gt;"global"&lt;/strong&gt; and &lt;strong&gt;"local"&lt;/strong&gt; may be a bit confusing here, as long as you can place Rx observable as a global variable, and you can &lt;a href="https://redux-dynamic-modules.js.org/#/"&gt;dynamically load&lt;/a&gt; redux stores. &lt;/p&gt;

&lt;p&gt;Rule of thumb here is: if something is forced to have globally unique ID getter as intended behavior - it is &lt;strong&gt;global&lt;/strong&gt;. No matter how ID is used - it can be&lt;code&gt;window[key]&lt;/code&gt;, or &lt;code&gt;require('stores/' + key)&lt;/code&gt;, or &lt;code&gt;dynamicModuleLocator.get(key)&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If something is intended to emerge within some other entity lifecycle - say, React or Angular component, or API queue manager, or whatever else - it is &lt;strong&gt;local&lt;/strong&gt;, despite the fact you &lt;em&gt;can&lt;/em&gt; assign it to &lt;code&gt;window[key]&lt;/code&gt;. Otherwise you would have to consider everything possibly global.&lt;/p&gt;

&lt;h3&gt;
  
  
  The missing link
&lt;/h3&gt;

&lt;p&gt;This may seem weird.&lt;/p&gt;

&lt;p&gt;I cannot recall any local &amp;amp; declarative state manager. With chances, you will name some esoteric or experimental state managers, but nothing from &lt;a href="https://2019.stateofjs.com/data-layer/other-tools/"&gt;"state of js" list&lt;/a&gt; &amp;amp; nothing I was able to find.&lt;/p&gt;

&lt;p&gt;And, probably, the answer is the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We are blending two different entities into one.&lt;/p&gt;

&lt;p&gt;We have &lt;strong&gt;state&lt;/strong&gt;, which is runtime-level, and we do not care on whether it is local or global; but what we do know is that it is best manipulated in imperative manner.&lt;/p&gt;

&lt;p&gt;And we have &lt;strong&gt;knowledge&lt;/strong&gt; about what is happening. We can affect this knowledge, but we can always predict the consequences of our affection; so, we can declare that we want to &lt;strong&gt;know&lt;/strong&gt; something about our system state.&lt;/p&gt;

&lt;p&gt;When we are using single store for both state and knowledge, we're doing something fundamentally wrong.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Models
&lt;/h3&gt;

&lt;p&gt;We've been thinking for the whole time that anything we were manipulating were just models. Model of checkbox, model of blog post, of SQL record, or relation graph; however, we were struggling a ton of times when we were curious on how to handle and marry our local state and remote state knowledge.&lt;/p&gt;

&lt;p&gt;But it is a way of thinking we brought from our experience of building the APIs.&lt;/p&gt;

&lt;p&gt;However, when you start to ask people how they make various complex applications with internal state on server, you will get the answer: they differ state and API responses.&lt;/p&gt;

&lt;p&gt;Usually, they use the following combination:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;knowledge layer: automatically caching wrappers around API calls with some invalidation logic. What is tricky here is that it is usually hidden.&lt;/li&gt;
&lt;li&gt;explicit state layer: sometimes it is &lt;a href="https://en.wikipedia.org/wiki/Finite-state_machine"&gt;finite state machine&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/State_diagram"&gt;statechart&lt;/a&gt;, sometimes it is some class with data. Sometimes - observables (RxJava, RxRuby, RxSwift, RxWhatever - you got the point) with logic encoded in its topology. Sometimes - some in-house or even ad-hoc solution, maybe even blended with other application parts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The solution
&lt;/h3&gt;

&lt;p&gt;I think it is the time to separate state and knowledge. This is even more vital for modern web apps than logic and view separation. We need to keep in mind that some variables we use are ones that came from external system (back-end or 3rd party), and we must keep in mind they were &lt;strong&gt;provided&lt;/strong&gt; to us. And some - are fully ours and we can manipulate them as we wish.&lt;/p&gt;

&lt;p&gt;We should clearly understand, that some of our strings, arrays and objects are coming from state, and some - from knowledge on system. &lt;strong&gt;Knowledge&lt;/strong&gt; is something global, something that describes the whole system - or parts of it that are available for us. Every single piece of knowledge should be labeled: you should know where this entity came from, and when it should be invalidated. &lt;strong&gt;GraphQL&lt;/strong&gt; is nice solution for it, but you can choose or build your own. Every piece of &lt;strong&gt;knowledge&lt;/strong&gt; should be transferable. Consider them as &lt;a href="https://en.wikipedia.org/wiki/Data_transfer_object"&gt;DTOs&lt;/a&gt;. Knowledge cannot have JS functions, or bindings to your local system - but if you need Turing-complete logic, you can transfer some Lisp-flavored object. I once had that experience, and keeping something like &lt;code&gt;{extractor: ["$fn", ["useMax"], ["return", ["ifelse", "useMax", "getMaxViewport", "getMinViewport"]]]}&lt;/code&gt; felt weird, but it worked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State&lt;/strong&gt; is how you represent current application state. It is OK if it is local - but keep in mind you will probably have to bind different parts of system together. Most important things here are that you can keep functions there, and that when you grab some data from &lt;strong&gt;knowledge&lt;/strong&gt; - e.g. you are editing blog post you already wrote - you should either copy the data, not re-use the object, or keep the diff, which is even better. Why it is better? Simple example: you have something like JIRA - with tons of fields to edit. You update one, and simultaneously someone else is altering another. If you will send the whole state to the server, you will overwrite another guy's work. If you only send your diff, you will not. Advanced version of that is called &lt;a href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type"&gt;CRDT&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, once again:
&lt;/h3&gt;

&lt;p&gt;You are working with two worlds in your application. &lt;/p&gt;

&lt;p&gt;One, the &lt;strong&gt;knowledge&lt;/strong&gt; is a reflection of something remote. You cannot download the whole DB to your browser, so you only get the parts of it. You can use &lt;strong&gt;imperative&lt;/strong&gt; &lt;code&gt;getBlogPost(id)&lt;/code&gt; or &lt;strong&gt;declarative&lt;/strong&gt; &lt;code&gt;@gql("blogPosts(id){...}") class extends Component&lt;/code&gt;. Both are fine, but when using declarative approach, you are hiding the ability to create complex logic you actually do not need.&lt;/p&gt;

&lt;p&gt;You should preserve data immutable. You can use &lt;a href="https://immutable-js.github.io/immutable-js/"&gt;ImmutableJS&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze"&gt;Object.freeze&lt;/a&gt;, use TypeScript's &lt;a href="https://www.typescriptlang.org/docs/handbook/classes.html#readonly-modifier"&gt;readonly&lt;/a&gt; or just keep an eye on that. If you do that, you can even do the trick and start keeping your &lt;strong&gt;knowledge&lt;/strong&gt; in Shared Worker or Service Worker.&lt;/p&gt;

&lt;p&gt;Second, the &lt;strong&gt;state&lt;/strong&gt; is your own kingdom. I personally advice to use &lt;a href="https://xstate.js.org/"&gt;XState&lt;/a&gt; to represent any complex piece of logic (anything bigger than the counter). But you can use anything you want. Just keep it away from &lt;strong&gt;knowledge&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Any interaction between this two worlds should me kept in userland and should be loud and clear.&lt;/p&gt;

&lt;p&gt;I'm not limiting you on some specific libraries, it is all on architecture and way of thinking. I suddenly understood few weeks ago that I was using this approach unknowingly and like a hidden pattern, but it is the thing that should be as explicit as possible.&lt;/p&gt;

&lt;p&gt;Give this idea a try, and you will see how your mind will slowly become lest restless.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
