<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Rahul Ramteke</title>
    <description>The latest articles on Forem by Rahul Ramteke (@iostreamer).</description>
    <link>https://forem.com/iostreamer</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%2F839103%2F6e6c5697-b3b6-4f8c-a371-98487448a8eb.png</url>
      <title>Forem: Rahul Ramteke</title>
      <link>https://forem.com/iostreamer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/iostreamer"/>
    <language>en</language>
    <item>
      <title>AI for software architecture</title>
      <dc:creator>Rahul Ramteke</dc:creator>
      <pubDate>Thu, 01 Feb 2024 14:40:09 +0000</pubDate>
      <link>https://forem.com/iostreamer/ai-for-software-architecture-3i77</link>
      <guid>https://forem.com/iostreamer/ai-for-software-architecture-3i77</guid>
      <description>&lt;p&gt;Designing a system, from small to big, starts as a vague process and then incrementally you narrow down&lt;br&gt;
on a particular approach. It'd be absurd to ask someone:&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Design a local first webapp with auto and manual saving&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Design a system which can onboard users, teams and organisations and manage role based access to resources&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
and expect a fully usable answer right out of the gate in 5 minutes. &lt;br&gt;
But the urge to do this with AI is quite present, if not immense. &lt;/p&gt;

&lt;p&gt;And to do so, would set you up for failure, more than it'd have by doing the same to you team member. Because&lt;br&gt;
they would understand context, and read between the lines and might actually give something valuable!&lt;/p&gt;

&lt;p&gt;And yet, I find myself talking to ChatGPT endlessly about how to build the features I mentioned above.&lt;/p&gt;


&lt;h1&gt;
  
  
  Your experience is context
&lt;/h1&gt;

&lt;p&gt;Before I dive in, let me show you what I mean. The local sync problem I mentioned before, well that was real.&lt;/p&gt;

&lt;p&gt;I am quite new to frontend and its mysterious ways of working, but I understand systems. I understand the &lt;br&gt;
fundamental blocks enough to reason about things, or at least get a sense of direction. &lt;/p&gt;

&lt;p&gt;I am also, a Functional Programming enthusiast, and tried my hand at FRP(Functional Reactive Programming), which led me to RxJS.&lt;/p&gt;

&lt;p&gt;Now, the folks who use RxJS as a daily driver must have gotten their wheels turning and good chance they solved it already. &lt;/p&gt;

&lt;p&gt;But not me, I don't use RxJS, I just understand pipelines!&lt;/p&gt;

&lt;p&gt;Pipelines can be mapped, filtered, buffered, merged but wait, the events that my app is generating is a stream &lt;br&gt;
and hence an Observable, even auto save is just a stream of button presses. I think there's something here that can solve my problem.&lt;/p&gt;

&lt;p&gt;And that's it!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A general sense of direction but with concrete ideas is just enough, that current LLMs require to help you with design.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lemme show you the final code which me and ChatGPT arrived at:&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;manualSaveTrigger$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fromEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;KeyboardEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metaKey&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrlKey&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nf"&gt;map&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;as&lt;/span&gt; &lt;span class="nx"&gt;StateChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setupSyncPipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;projectId&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;eventSource$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;NonNullable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SyncManagerState&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eventSource$&lt;/span&gt;&lt;span class="dl"&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;syncManagerStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UseBoundStore&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StoreApi&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SyncManagerState&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="nx"&gt;bufferTimeInMs&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;syncManagerState$&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;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SyncManagerState&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;syncManagerStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nx"&gt;syncManagerStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;syncManagerState$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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;sharedEventSource$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;eventSource$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;share&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bufferedEvents$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sharedEventSource$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;syncManagerStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setSyncStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unsynced&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="nf"&gt;bufferWhen&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bufferTimeInMs&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Emit when buffer time elapses&lt;/span&gt;
          &lt;span class="nx"&gt;manualSaveTrigger$&lt;/span&gt;    &lt;span class="c1"&gt;// Or when manual save is triggered&lt;/span&gt;
        &lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bufferedEvents$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mergeEvents&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nf"&gt;withLatestFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syncManagerState$&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isSyncingAllowed&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Check if syncing is allowed&lt;/span&gt;
        &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;syncManagerStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setSyncStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;syncing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="nf"&gt;concatMap&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;mergedEvents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
            &lt;span class="nx"&gt;ajax&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;server_sequence&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="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getSyncApiUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;updated_artifacts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mergedEvents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;server_sequence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serverSequence&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;withCredentials&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&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;syncManagerStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setSyncStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;synced&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="nx"&gt;syncManagerStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setServerSequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;server_sequence&lt;/span&gt;&lt;span class="p"&gt;);&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="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;syncManagerStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setSyncStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;errored&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="nx"&gt;syncManagerStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setIsSyncingAllowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Merged event synced:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&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="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;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;Error syncing merged event:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;complete&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;All merged events synced&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;syncManagerStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setSubscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mergeEvents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StateChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Merge logic here&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newState&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;merged&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; 
        &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSyncApiUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;getBaseAPIPath&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;/project/sync/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a lot of code, but that's not important. What's important is it works, I understand how it works, and I got this by understanding basics.&lt;/p&gt;



&lt;h1&gt;
  
  
  It's the new engineer in your team
&lt;/h1&gt;

&lt;p&gt;The one who is quite eager to execute but needs some hand holding, and with good direction&lt;br&gt;
can deliver exactly what you want. That's what current LLMs are when it comes to architecture.&lt;/p&gt;

&lt;p&gt;You have to be the one boucing ideas, guiding and more importantly verifying, because they'll definitely make mistakes. Here are the ones it made in my case:&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;When it missed an operation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Indeed, you are correct. Let's integrate the merging of events into the updated pipeline, ensuring that the merged events and the sequence number are correctly handled in each API call.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;After reviewing that it missed a crucial check:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yes, you are correct. The current implementation does not check if syncing is allowed before proceeding with the API call. This check is crucial, especially in the scenario where the state is set to 'errored' and further syncing is supposed to be halted.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;When it just assumed how TS works:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You're correct to question the typecasting of useStore to Observable&amp;lt;StoreState&amp;gt; in the RxJS pipeline.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;When it came up with the wrong implementation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You're correct in your understanding. Placing the tap operator after bufferTime means it will only execute after the specified time interval (n seconds) has passed and the events have been buffered.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;Once again, wrong implementation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yes, you're correct. Setting the 'unsynced' status after bufferTime would introduce the same issue as discussed earlier. The 'unsynced' status would only be set after the buffering period has elapsed, not immediately when events start arriving.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;When it fumbled manual save:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You're absolutely correct. If the manualSave$ observable emits an empty array, and it's merged with the event source observable, there's a risk of syncing that empty array instead of the actual buffered events.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
But what it lacks in precision, it makes up for in speed. The chat interaction might look long but the conversation lasted&lt;br&gt;
for barely an hour and by the end of it, I had exactly what I needed.&lt;/p&gt;

&lt;p&gt;Here are some more design problems I could rush through quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;That user, projects, organisation and resource problem I mentioned before, very real.&lt;/li&gt;
&lt;li&gt;I also needed to create a basic file system abstraction, I know how trees work but need help with applying that knowledge
to the app I am building.&lt;/li&gt;
&lt;li&gt;In the &lt;a href="https://metz.sh/"&gt;metz&lt;/a&gt; runtime I needed a better way to detect connections, I had an idea around a graph based approach
but needed some oversight.&lt;/li&gt;
&lt;/ul&gt;



&lt;h1&gt;
  
  
  Compiler of Ideas
&lt;/h1&gt;

&lt;p&gt;A programming language compiler, takes our intention of what we want to do, and then does all the hard work of&lt;br&gt;
making it a reality.&lt;/p&gt;

&lt;p&gt;And that's how I see my interactions with AI for design. It too has "syntax" errors, where if you don't start&lt;br&gt;
with something concrete it'll "crash" and give garbage answers.&lt;/p&gt;

&lt;p&gt;Designing a system needs in-depth analysis, but not just of one idea, rather of many ideas. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;System design is not just about choosing the right thing, but knowing there are other right things and this thing is the most right for us.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is where iteration speed matters. The ability to try things out quickly, create a thesis and compare, is crucial to arriving at an informed decision.&lt;/p&gt;

&lt;p&gt;And this is exactly were AI shines.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PS: This post appeared first at &lt;a href="https://lab.metz.sh/ai-for-architecture"&gt;metz's blog&lt;/a&gt;.&lt;br&gt;
We at &lt;a href="https://metz.sh/"&gt;metz&lt;/a&gt; are building a platform where you can just code to create architecture diagrams.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Saving cost with timeout latches in JavaScript</title>
      <dc:creator>Rahul Ramteke</dc:creator>
      <pubDate>Mon, 18 Jul 2022 09:11:38 +0000</pubDate>
      <link>https://forem.com/iostreamer/saving-cost-with-timeout-latches-in-javascript-2m19</link>
      <guid>https://forem.com/iostreamer/saving-cost-with-timeout-latches-in-javascript-2m19</guid>
      <description>&lt;p&gt;I maintain this app called:&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://www.casset.app" rel="noopener noreferrer"&gt;
      casset.app
    &lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
which essentially live streams what song I am listening on spotify and lets users join in and sync with me.&lt;br&gt;
It doesn't really stream audio buffers, just the song title.

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

&lt;p&gt;And the architecture is pretty straight forward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Poll spotify api in background&lt;/li&gt;
&lt;li&gt;maintain state in memory&lt;/li&gt;
&lt;li&gt;push state change to client via websockets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it works quite well, acceptable delay, no rate limits hit(hard to when it's just my user getting polled).&lt;br&gt;
But every month, I get an invoice of 25$ from Digital Ocean.&lt;/p&gt;

&lt;p&gt;That happens because I use their k8s cluster and a load balancer. Which I know is an overkill for something like this.&lt;/p&gt;

&lt;p&gt;And that's why I decided to not only move away to something simpler and cheaper but also explore can we only pay for the work that we do?&lt;/p&gt;
&lt;h2&gt;
  
  
  Architecture Overhaul
&lt;/h2&gt;

&lt;p&gt;Firstly we need to move away from the "always on" mode to "on demand" mode.&lt;br&gt;
Does the tree fall in the forest only when we observe it? In our case, yes it does. Because then we don't have to render/calculate anything unnecessarily.&lt;/p&gt;

&lt;p&gt;So we remove the socket layer, and let the client poll our system.&lt;/p&gt;

&lt;p&gt;Now we have two polls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client polling our system&lt;/li&gt;
&lt;li&gt;System polling Spotify&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is it ok if we take the shortcut and couple these two polling? That is, call Spotify API only if client calls our system.&lt;/p&gt;

&lt;p&gt;That can work in theory, but with this our rate of API requests to spotify gets coupled with number of clients. One client is ok, maybe 10 even, but 100? 100,000?&lt;/p&gt;

&lt;p&gt;That's when we would have problems. Problems like, rate limit and quota exhaustion.&lt;br&gt;
Also, let's say I am listening to a song for a few minutes, does it even make sense to call spotify API 100,000k times to check current track?&lt;/p&gt;

&lt;p&gt;With this, we see that coupling those two systems isn't a good idea. So what do we do next? &lt;br&gt;
We need to poll spotify but not unnecessarily, only when we have intent, but we don't want to tightly couple with incoming requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Weak coupling?&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Let's say we have a timer with us for polling spotify, say 10s. Our system will poll spotify every second for 10s and then stop. Unless a request comes, then the timer gets reset to 10s and the cycle starts again.&lt;br&gt;
If there are 100,000 requests coming to the system, the max a request can do is reset the timer, it doesn't affect the poll rate for spotify, just elongates the process.&lt;/p&gt;

&lt;p&gt;It's best described visually here:&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://observablehq.com/d/2531ae77ca3d9231" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--hCwDibD3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://static.observableusercontent.com/thumbnail/2ab1ef518b7750bbbd1f323e027ffdc3c21e990c7b17d4670aef242d10ded017.jpg" height="400" class="m-0" width="640"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://observablehq.com/d/2531ae77ca3d9231" rel="noopener noreferrer" class="c-link"&gt;
          Timeout latch / iostreamer | Observable
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          It's a leaky bucket which leaks at constant rate unless reset by some action. In this example, clicking!
Checkout the project here
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--OGylEeWA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://static.observablehq.com/favicon-512.0667824687f99c942a02e06e2db1a060911da0bf3606671676a255b1cf97b4fe.png" width="512" height="512"&gt;
        observablehq.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Timeout latch
&lt;/h2&gt;

&lt;p&gt;It's straight forward to model this with simple timers. For example, we start a &lt;code&gt;setTimeout&lt;/code&gt; and whenever we want to reset, we clear that timeout and start again.&lt;/p&gt;

&lt;p&gt;But I didn't want the overhead of creating and deleting timers just for resetting the clock.&lt;/p&gt;

&lt;p&gt;So I created a custom scheduler, which ticks every 1ms. On the other hand, we have a &lt;code&gt;latch&lt;/code&gt;, essentially just an object with a counter.&lt;br&gt;
The scheduler's job is to decay the latches by decrementing the counters.&lt;br&gt;
In this universe, scheduler creates time using ticks, and latches experience that time using associated counters.&lt;/p&gt;

&lt;p&gt;This is fairly simple and straightforward, but as I mentioned before, I wanted to explore can we only pay for whatever actual work we do?&lt;/p&gt;

&lt;p&gt;Running a scheduler indefinitely still means we are in an "always on" mode. What's the point of creating time if there are no entities to observe it?&lt;/p&gt;

&lt;p&gt;And that's final thing that we needed to do, stop the scheduler if all latches are done, or cancelled.&lt;/p&gt;

&lt;p&gt;If something new is added, or an old latch gets reset then start the engine once again.&lt;/p&gt;

&lt;p&gt;The code is maintained here and published to npm as well.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/iostreamer-X"&gt;
        iostreamer-X
      &lt;/a&gt; / &lt;a href="https://github.com/iostreamer-X/timeout-latch"&gt;
        timeout-latch
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A simple timeout latch. Like a reverse leaky bucket.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
timeout-latch&lt;/h1&gt;
&lt;p&gt;A simple timeout latch. Like a reverse leaky bucket.&lt;/p&gt;
&lt;p&gt;It's a simple callback based mechanism to get notified when a timeout has occurred and reset that timeout
if need arises
Checkout the visual demo &lt;a href="https://observablehq.com/d/2531ae77ca3d9231" rel="nofollow"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Why not plain timeout?&lt;/h2&gt;
&lt;p&gt;Plain timeouts might not work that easily. For example, one might start a timeout and manage state around it.&lt;/p&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;run&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-en"&gt;setTimeout&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;
        &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
            &lt;span class="pl-c"&gt;// your callback       &lt;/span&gt;
        &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
        &lt;span class="pl-c1"&gt;3000&lt;/span&gt;
    &lt;span class="pl-kos"&gt;)&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;
&lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;reset&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c"&gt;// when you want to reset the timer&lt;/span&gt;
    &lt;span class="pl-en"&gt;run&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;But we realise that resetting only works when the timeout has completed its work. If we reset before that
then we simply have two timeouts!&lt;/p&gt;
&lt;p&gt;To counter this we can clear the previous timer and start again. And it works but has the overhead of cancelling and creating new timers. Also, it's a timer…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/iostreamer-X/timeout-latch"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Why is this better?
&lt;/h2&gt;

&lt;p&gt;So we already established that in this case "on demand" is better than "always on". &lt;br&gt;
And in "on demand" mode as well, we wanted to be truly "on demand", that is expend resources only when necessary.&lt;/p&gt;

&lt;p&gt;With the current setup, especially with timeout-latch, we are in a state where nothing runs unless necessary, and it halts if the intent to run isn't there anymore.&lt;/p&gt;

&lt;p&gt;This property is extremely beneficial if we look at serverless or edge functions.&lt;br&gt;
That's a model where you do pay for whatever you execute. &lt;/p&gt;

&lt;p&gt;Even for simple apps on Digital Ocean there's a minimum of 5$ you'd have to pay.&lt;br&gt;
But for a platform that takes the "server" away from you, one can truly embrace the burstiness nature of work.&lt;/p&gt;

&lt;p&gt;And this serves as an example where we transformed polling(very continuous) to something that's bursty and "on demand".&lt;/p&gt;

&lt;p&gt;And that concludes my cost cutting process, the things you have to do in this economy 😁&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Seamlessly offloading typescript compilation</title>
      <dc:creator>Rahul Ramteke</dc:creator>
      <pubDate>Tue, 26 Apr 2022 09:11:18 +0000</pubDate>
      <link>https://forem.com/iostreamer/seamlessly-offloading-typescript-compilation-b8n</link>
      <guid>https://forem.com/iostreamer/seamlessly-offloading-typescript-compilation-b8n</guid>
      <description>&lt;p&gt;I picked the problem of my macbook pro being an absolute snail under load, mostly because I wanted to play around and experiment while learning something. &lt;/p&gt;

&lt;p&gt;Sure I got my standard VS Code, a terminal, a browser, slack, postman and some other programs running, but there comes a time when I change something in my code and in response the macbook starts preparing for a lift off.&lt;/p&gt;

&lt;p&gt;You see I have this typescript project, not too big, but not too small either. I keep a build task running in background which incrementally compiles code whenever I change it.&lt;/p&gt;

&lt;p&gt;And here is the usual ram usage:&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/http%3A%2F%2Fiostreamer.me%2Fassets%2Farticle_images%2Ftscw.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/http%3A%2F%2Fiostreamer.me%2Fassets%2Farticle_images%2Ftscw.png" alt="Heavy ram usage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking up and fixing VS Code ram usage is fairly easy, but what about that node process? That’s the one I have no idea how to fix. I mean it compiles stuff and it takes a lot of juice, that’s all I know.&lt;/p&gt;

&lt;p&gt;I can’t throw hardware at this problem! Or so I thought. Well I can’t upgrade my RAM or my CPU even for that matter. But, I do have nice PC sitting idle when I work. It has 16G of RAM, and a Ryzen 1600 for CPU. Fun fact, Ryzen 1600 is supposed to be a 6-core processor but somehow AMD manafacturing plants messed up and released a few 1600s with 8 cores. And somehow I got lucky.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;The problem is straightforward, use the PC to compile the code residing on my macbook.&lt;/p&gt;

&lt;p&gt;But I have come to depend on nodemon and auto reload on change. And that’s something I don’t want to miss out on. So let’s throw in this constraint as well. The solution should work as good as shown below where nodemon restarts my server as soon as I change a file and save it:&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/http%3A%2F%2Fiostreamer.me%2Fassets%2Farticle_images%2Fauto_reload.gif" 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/http%3A%2F%2Fiostreamer.me%2Fassets%2Farticle_images%2Fauto_reload.gif" alt="How it should work"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;What if we listened for changes in our filesystem, especially if done to a particular directory, and then we create a zip, send it to PC over network, the PC compiles it, and sends back a zip, we unzip it? Voila, we have got ourselves a working solution! And along with that we have got ourselves a whole lot of lag! This would slow down to the point of defeating the whole purpose.&lt;/p&gt;

&lt;p&gt;I am quite convinced that sending code back and forth will be a bottleneck if I come up with something of my own. It’d be better if we lean on something native, I mean this is a problem someone else must have solved. And sure someone had. It’s called NFS(Network File system), and it’s quite old and widely used.&lt;/p&gt;

&lt;p&gt;The idea is simple, mount macbook’s disk on PC and then ask PC to compile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                          +--------------------------+
                          | +--------------+         |
                          | |Compiler      |         |
                          | +-+------------+         |
                          |   |                      |
                          |   |                      |
                          |   |Compile mounted       |
                          |   |project               |
                          |   |                      |
                          |   |                      |
                          |   |                      |
                          +---v---------+            |
                          |             |            |
+---------+               |             |            |
|         +--------------&amp;gt;+ Mounted     |            |
| Macbook |   Mount       | Project     |            |
|         |               |             |            |
+---------+               |             |            |
                          |             |            |
                          +-------------+            |
                          |                          |
                          |                          |
                          |                          |
                          |                          |
                          |                          |
                          |                          |
                          |      PC                  |
                          +--------------------------+

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Figure 1&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And as the name &lt;code&gt;Network File System&lt;/code&gt; suggests, it lets you access remote machines’ disk as if you are accessing it locally. And that’s the beauty of it. Anything I change on my machine, gets transmitted to the remote machine instantly(well ignoring some network latency) and vice versa.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explaination
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Figure 1&lt;/em&gt;&lt;/strong&gt; sheds some light on this simple architecture. The remote machine has the compiler installed, and to actually compile it, all that needs to be done is compile the directory.&lt;/p&gt;

&lt;p&gt;And yes, that directory is a mounted one but that doesn’t matter! It’s a directory nonetheless and the compiler is well versed in talking to it.&lt;/p&gt;

&lt;p&gt;Well, ok, sure the compiler can handle a mounted directory but does it help our cause? Absolutely!&lt;/p&gt;

&lt;p&gt;The directory is mounted on remote machine, and it has the compiler as well. It’s pretty straightforward for the remote machine to go ahead and provide some resources to the compiler and let it do its job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Offloading succesfull!&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;I tried this solution and first I needed to setup NFS server on my mac. &lt;a href="https://www.bresink.com/osx/NFSManager.html" rel="noopener noreferrer"&gt;NFS Manager&lt;/a&gt; is a nice little free tool that came handy. It’s easy to configure and lets you control a lot of things.&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/http%3A%2F%2Fiostreamer.me%2Fassets%2Farticle_images%2Fnfsm.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/http%3A%2F%2Fiostreamer.me%2Fassets%2Farticle_images%2Fnfsm.png" alt="Here are my settings for NFS Manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that my macbook is mountable, I needed to tell my PC to actually mount it. My PC runs a Ubuntu, so all the commands for PC will be linux specific.&lt;/p&gt;

&lt;p&gt;In essence, I need to use the &lt;code&gt;mount&lt;/code&gt; command and tell it the IP address of my macbook and the directory it’s sharing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zero Conf
&lt;/h3&gt;

&lt;p&gt;It enables any device to find other devices on the network and contact them. So if a device has the zero-conf daemon running, and is brought on to a network, it has the capability to find other zero-conf enabled devices.&lt;/p&gt;

&lt;p&gt;But what does it mean to ‘know’ devices on the network? Well a part of the answer is the name of the device, or more specifically the hostname.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mDNS(Multicast DNS)&lt;/code&gt; is another service on which Zero Conf relies on and it powers the hostname resolution for connected devices.&lt;/p&gt;

&lt;p&gt;Each device on the network has a name it can use, and by default other devices can access it through the hostname: &lt;code&gt;&amp;lt;device-name&amp;gt;.local&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Well &lt;strong&gt;&lt;em&gt;access&lt;/em&gt;&lt;/strong&gt; is not quite right, just like DNS, mDNS is also a protocol which maps hostnames to IP addressess. And that’s all it does, it resolves the hostname into a valid IP address.&lt;/p&gt;

&lt;p&gt;Once you have the IP you can basically do all the networking you want to do.&lt;/p&gt;

&lt;p&gt;The beauty is, you don’t have to remeber ip addresses anymore, if your device restarts and your router gives it a different IP address, it simply doesn’t matter. We have a hostname for the device now, and mDNS to resolve it.&lt;/p&gt;

&lt;p&gt;It comes by default in macOS, and in fact you can test it right away. &lt;code&gt;&amp;lt;your-laptop's-name&amp;gt;.local&lt;/code&gt; is the hostname of your macbook. And if you have a server running(can try running with &lt;code&gt;python -m SimpleHTTPServer&lt;/code&gt;), you can access it using that hostname.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up NFS
&lt;/h3&gt;

&lt;p&gt;Let’s continue our NFS journey with this newfound knowledge of &lt;code&gt;.local&lt;/code&gt; domains. In my setup, the name of my PC is &lt;code&gt;kaer-morhen&lt;/code&gt; and my macbook is named &lt;code&gt;bianco&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once again:&lt;br&gt;&lt;br&gt;
PC/Remote machine = &lt;code&gt;kaer-morhen&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Macbook = &lt;code&gt;bianco&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I have created a directory on PC as &lt;code&gt;/mnt/bianco&lt;/code&gt;. If a new device comes up it’ll follow the same pattern. Now, mounting is simple, as discussed before, we will have to use the mount command, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mount bianco.local:/System/Volumes/Data/Users/iostreamer /mnt/bianco

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This comes with a limitation that one’d have to mount it everytime I boot the PC. To automate it, I followed the steps mentioned &lt;a href="https://linuxize.com/post/how-to-mount-an-nfs-share-in-linux/#automatically-mounting-nfs-file-systems-with-etcfstab" rel="noopener noreferrer"&gt;here&lt;/a&gt; and created an entry in &lt;code&gt;/etc/fstab&lt;/code&gt; and let the OS handle it for me. Now all that mounting stuff is done behind the scenes automatically!&lt;/p&gt;

&lt;p&gt;Voila! Our macbook will be automatically mounted on PC whenever the PC boots.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Compiler
&lt;/h3&gt;

&lt;p&gt;For this particular project, I need the typescript compiler. Installing it is as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i -g typescript

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To compile the project all one needs to do is run the command &lt;code&gt;tsc&lt;/code&gt; in the project directory. This parses your tsconfig.json, picks up source directories, compiles file and puts them in the output directory. But we also need it to watch for changes done to the source directories and then recompile if anything changes. That can be done with compiling in watch mode: &lt;code&gt;tsc -w&lt;/code&gt;. This would block your shell and start watching for changes.&lt;/p&gt;

&lt;p&gt;Here’s a script I wrote which &lt;code&gt;SSHs&lt;/code&gt; into the remote machine, goes to the appropriate directory and starts compilation in watch mode. I named this script &lt;code&gt;rcw&lt;/code&gt;(Remote compile watch). It basically picks up the current working directory as string, and replaces folder names such that it matches the mount folder on remote machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env zsh

cwd=`pwd`
cwd="${cwd/Users/mnt}" // Syntax for replacing substrings
cwd="${cwd/iostreamer/bianco}"
ssh -tt iostreamer@kaer-morhen.local "cd $cwd &amp;amp;&amp;amp; tsc -w"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s try to run it, change the files and see if automatically compiles the changes or not:&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/http%3A%2F%2Fiostreamer.me%2Fassets%2Farticle_images%2Ftcf.gif" 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/http%3A%2F%2Fiostreamer.me%2Fassets%2Farticle_images%2Ftcf.gif" alt="No auto compile"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Lo and behold, it doesn’t work!
&lt;/h4&gt;

&lt;p&gt;What did we miss? Did we miss something? Let’s find out!&lt;/p&gt;

&lt;h2&gt;
  
  
  The catch
&lt;/h2&gt;

&lt;p&gt;Why did it not work? We have mounted correctly, it even compiles properly and one can even see the compiled files locally. Then what’s stopping it to react to changes done to files?&lt;/p&gt;

&lt;p&gt;Well, to be blunt, it does work. It’s just clunk and slow in my experience(YMMV).&lt;/p&gt;

&lt;h3&gt;
  
  
  What is inotify?
&lt;/h3&gt;

&lt;p&gt;Well &lt;code&gt;inotify&lt;/code&gt; is a Linux API/ Sub system. You can ask this API to tell you whenever a change is done to a directory or its files. When you run &lt;code&gt;tsc -w&lt;/code&gt;, i.e. compile in watch mode, that’s exactly what the typescript compiler does. It sets up a watcher, which is notified when source directories change.&lt;/p&gt;

&lt;p&gt;In our case, the NFS client running on linux(PC) is the one handling changes done by macbook. And these changes are all immediate, very snappy. You can verify by creating a file locally and then &lt;code&gt;SSHing&lt;/code&gt; in to remote machine and using the &lt;code&gt;watch&lt;/code&gt; command to see the contents of the file at let’s say an interval of 0.1s. As soon as you change the contents of the file locally, you’d see it getting reflected immediately through the &lt;code&gt;watch&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;The issue seems to be with NFS client and inotify. It’s not that it doesn’t work, but in my experience it’s quite slow, to the extend you can’t depend on it. From what I observed, the content of the file change immediately but the NFS client takes its time to contact inotify. Eventually it does, but who wants to wait?&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution: Part 2
&lt;/h2&gt;

&lt;p&gt;After Googling for like 5 minutes I came across this interesting project called &lt;a href="https://github.com/mhallin/notify-forwarder" rel="noopener noreferrer"&gt;notify-forwarder&lt;/a&gt;. It works on a very simply principle, forward it manually.&lt;/p&gt;

&lt;p&gt;It’s a program which works in 2 modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;watch 

&lt;ul&gt;
&lt;li&gt;When working in watch mode, it listens for changes locally and transmits those changes to the specified machine.&lt;/li&gt;
&lt;li&gt;When watching, you have to specify the remote ip, as well as the remote directory path.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;receive 

&lt;ul&gt;
&lt;li&gt;When working in receive mode, it simply listens for changes done to the directory.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;To be more precise, this program simply tells &lt;code&gt;some&lt;/code&gt; change has been done to a file. And when listening for events(receive mode), it simulates an &lt;code&gt;ATTRIB&lt;/code&gt; event. This event is fired when an attribute of the file is changed.&lt;/p&gt;

&lt;p&gt;And the obvious drawback is that, not all compilers/build systems respect &lt;code&gt;ATTRIB&lt;/code&gt; events.&lt;/p&gt;

&lt;p&gt;Thankfully, typescript does.&lt;/p&gt;

&lt;p&gt;Now, all we have to do is run this program in receive mode on my PC. And then in watch mode locally. For PC, I didn’t want to run it manually, so I created a service, which can be handled by &lt;code&gt;systemd&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note: I had no prior experience with systemd services and followed this &lt;a href="https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/" rel="noopener noreferrer"&gt;guide&lt;/a&gt; to create it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Script to run in receive mode&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;notify-forwarder receive

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;.service file for the script&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Unit]
Description=Notify Forwarder

[Service]
Type=simple
ExecStart=/bin/bash /usr/local/bin/notify_receive

[Install]
WantedBy=multi-user.target

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For my macbook, I needed a script which runs &lt;code&gt;notify-forwarder&lt;/code&gt; in watch mode, watches the current directory and sends the changes to PC(kaer-morhen). I named it &lt;code&gt;nk&lt;/code&gt; (Notify Kaer-Morhen)&lt;/p&gt;

&lt;p&gt;Here’s the script for same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ip=`dscacheutil -q host -a name kaer-morhen.local | grep ip_address | awk -v FS=': ' '{print $2}'`
cwd=`pwd`
cwd="${cwd/Users/mnt}"
cwd="${cwd/iostreamer/bianco}"
notify-forwarder watch -c $ip . $cwd

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is how it looks when it all comes together:&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/http%3A%2F%2Fiostreamer.me%2Fassets%2Farticle_images%2Fauto_reload.gif" 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/http%3A%2F%2Fiostreamer.me%2Fassets%2Farticle_images%2Fauto_reload.gif" alt="Final version"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;This was a day’s hack and I got to learn so much! But all of it fades when compared to this one learning. You see, before starting I thought achieving something like this smoothly would need some genius level hacks or code.&lt;/p&gt;

&lt;p&gt;But it did not. I just stumbled from one problem to another till I managed to hack together a part elegant, a part messy solution. This is definitely not a genius level code.&lt;/p&gt;

&lt;p&gt;Getting it done &lt;code&gt;&amp;gt;&lt;/code&gt; Waiting to learn some godsent tools and creating that perfect thing.&lt;/p&gt;

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

&lt;p&gt;This is definitely not a &lt;code&gt;Compiler as a Service&lt;/code&gt; product and I doubt it’s going to be for a long time. But that’s not going to stop me from monetising it in my home. My roommate has a similar setup, and I am thinking of an AWS like model where 1 CPU minute = 2 dishes they wash.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>dns</category>
    </item>
    <item>
      <title>Threads in NodeJS: Going beyond eventloop using Rust</title>
      <dc:creator>Rahul Ramteke</dc:creator>
      <pubDate>Sat, 09 Apr 2022 20:08:18 +0000</pubDate>
      <link>https://forem.com/iostreamer/threads-in-nodejs-going-beyond-eventloop-using-rust-3ch7</link>
      <guid>https://forem.com/iostreamer/threads-in-nodejs-going-beyond-eventloop-using-rust-3ch7</guid>
      <description>&lt;p&gt;&lt;strong&gt;Circumventing the single thread bottleneck&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Index:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
NodeJS Refresher

&lt;ul&gt;
&lt;li&gt;A brief overview of how eventloop works internally&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Let's block the main thread

&lt;ul&gt;
&lt;li&gt;How a simple code can bring down the performance of NodeJS&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
A qr generator service

&lt;ul&gt;
&lt;li&gt;A realistic example and the results of load testing&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
How to improve?

&lt;ul&gt;
&lt;li&gt;Can we do better than Node?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Rust solution

&lt;ul&gt;
&lt;li&gt;Using rust and neon to save the day&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Comparison

&lt;ul&gt;
&lt;li&gt;It's a number's game&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Conclusion

&lt;ul&gt;
&lt;li&gt;It's all about choosing the best tool for the job&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  NodeJS refresher
&lt;/h3&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
At this point, we have all heard and read how nodejs is singlethreaded but not really. But just in case, here's a refresher:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NodeJS relies on the concept of event loop. The idea is to ask the os/kernel to do the heavylifting and expect a signal saying 'hey, this is done'.

&lt;ul&gt;
&lt;li&gt;Each os has their own thing going on, linux has &lt;code&gt;epoll_wait&lt;/code&gt;, osx has &lt;code&gt;kqueue&lt;/code&gt; and windows has something weird.&lt;/li&gt;
&lt;li&gt;These kernel api calls are the ones doing the actual job. It kinda looks like this
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//pseudocode&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;epoll_wait&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;socket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// do something&lt;/span&gt;
        &lt;span class="c1"&gt;// or in our case, execute the relevant callback&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;ul&gt;
&lt;li&gt;NodeJS doesn't have a one size fit all event loop, rather it has a phased setup.

&lt;ul&gt;
&lt;li&gt;For example, it checks timers(&lt;code&gt;setTimeout&lt;/code&gt; etc) first.

&lt;ul&gt;
&lt;li&gt;Here it's the OS's show again, and it uses &lt;code&gt;epoll&lt;/code&gt; or equivalent to know if it needs to execute a callback or not.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Then we have the microtask queue, which handles &lt;code&gt;promises&lt;/code&gt; and &lt;code&gt;nextTicks&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;...And more, checkout &lt;a href="https://www.youtube.com/watch?v=PNa9OMajw9w"&gt;this&lt;/a&gt; video for full picture&lt;/li&gt;
&lt;li&gt;At the end of the phased setup, it checks if there are still any more events that it needs to handle or wait for. If yes, the loop continues, if not the loop and the program exits.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;After getting a signal saying 'hey, this is done', the associated callback that you provided is executed.

&lt;ul&gt;
&lt;li&gt;Now mind you, the loop itself is what's single threaded. The tasks that node does in the loop, all on one thread.&lt;/li&gt;
&lt;li&gt;And the associated callback that it needs to run? Well, you guessed it, the same event loop thread.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;And now you case see why there might be some confusion around the execution. Afterall, it's singlethreaded but not really. &lt;/p&gt;

&lt;p&gt;Also, what happens if the callback you provided is trying to calculate the meaning of life? That's when we have a problem, because now our eventloop isn't going to do anything until the callback function's execution is complete.&lt;/p&gt;

&lt;p&gt;That's what we mean by blocking the main thread in NodeJS.&lt;/p&gt;


&lt;h3&gt;
  
  
  Let's block the main thread
&lt;/h3&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Let's say we have a NodeJS &lt;code&gt;express&lt;/code&gt; server with us. And on each request, we calculate a cryptographic hash of given query parameters. And just to stress the system, we do this hashing 500k times and then return the result back.&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hashedString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;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="mi"&gt;500000&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="c1"&gt;// do fancy hashing&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;hashedString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;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;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;text&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;result&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`App listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;Based on what we discussed in previous section, we can see how this setup can backfire and undermine the performance of NodeJS. But to show again:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;NodeJS starts up, and starts executing our script&lt;/li&gt;
&lt;li&gt;It asks OS to tell when the server starts&lt;/li&gt;
&lt;li&gt;It asks OS to also tell when that server receives a connection request&lt;/li&gt;
&lt;li&gt;And now the grand loop runs in phased manner, checking timer first, then i/o and so on&lt;/li&gt;
&lt;li&gt;Since NodeJS still has some events that it's waiting for(server connection requests), the loop doesn't quit&lt;/li&gt;
&lt;li&gt;Let's say someone hits our api, then the os tells NodeJS of that event&lt;/li&gt;
&lt;li&gt;In the next iteration/tick of the grand phased loop, it checks timers first, finds nothing and then it checks i/o&lt;/li&gt;
&lt;li&gt;It finds that there's a request, and promptly starts executing associated callback&lt;/li&gt;
&lt;li&gt;Once the execution of callback is finished, the grand phased loop is iterated again and the queues are checked for more connection requests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Now, our callback isn't very easy breezy, it can take a good amount of time to execute, relatively speaking. &lt;/p&gt;

&lt;p&gt;And that will delay the next iteration of the grand phased loop, which will delay knowing if there's a new connection or not. And that's one very good way of losing i/o performance in NodeJS.&lt;/p&gt;

&lt;p&gt;If you look at the code, it's quite innocent looking, nothing weird about it. But one nefarious loop or thread blocking operation is all it takes.&lt;/p&gt;


&lt;h3&gt;
  
  
  A qr generator service
&lt;/h3&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
The previous example of hash calculation isn't very realistic. So let's say we have to build a service which can create a qr image of any given text. &lt;/p&gt;

&lt;p&gt;This service will have a simple &lt;code&gt;GET&lt;/code&gt; api which will take text in query params. After that it will return a base64 string representing the QR version of given text.&lt;/p&gt;

&lt;p&gt;Let's use NodeJS and commonly used libraries for this service. Here's how it looks in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;QRCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;qrcode&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;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;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;QR TEST&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;result&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;QRCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDataURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`App listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
Voilà! We have what we needed. A very simple script which does what we planned to do. But here's the catch, if you look at the source code of &lt;code&gt;qrcode&lt;/code&gt; library, you'll find there are no async calls. It's all done in one synchronous function.&lt;/p&gt;

&lt;p&gt;And now our code looks a lot like the 500k hashing one. But how bad can it really be?&lt;/p&gt;

&lt;p&gt;To answer that, I setup &lt;code&gt;pm2&lt;/code&gt; for some advanced monitoring and &lt;code&gt;artillery&lt;/code&gt; for load testing. Here's how it went:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─ Custom Metrics ───────────────────────────────────────────┐┌─ Metadata ────────────────────────────────────────────────────────────┐
│ Used Heap Size                                  23.74 MiB  ││ App Name              index                                           │
│ Heap Usage                                        40.33 %  ││ Namespace             default                                         │
│ Heap Size                                       58.87 MiB  ││ Version               1.0.0                                           │
│ Event Loop Latency p95                            10.78 ms ││ Restarts              0                                               │
│ Event Loop Latency                                3.2 ms   ││ Uptime                2m                                              │
│ Active handles                                       1608  ││ Script path           /home/iostreamer/projects/node-qr-test/index.js │
│ Active requests                                         0  ││ Script args           N/A                                             │
│ HTTP                                       269.86 req/min  ││ Interpreter           node                                            │
│ HTTP P95 Latency                                    16 ms  ││ Interpreter args      N/A                                             │
│ HTTP Mean Latency                                    7 ms  ││ Exec mode             fork                                            │
│                                                            ││ Node.js version       16.13.2                                         │
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--------------------------------
Summary report @ 16:49:34(+0530)
--------------------------------

http.codes.200: .............................49994
http.request_rate: ..........................356/sec
http.requests: ..............................49994
http.response_time:
  min: ......................................1
  max: ......................................97
  median: ...................................15
  p95: ......................................29.1
  p99: ......................................47
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;Some important stats out of this exercise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;event-loop-latency:
p95                     10.78 ms
current                 3.2 ms

http.response_time:
  min: ................ 1 ms
  max: ................ 97 ms
  median: ............. 15 ms
  p95: ................ 29.1 ms
  p99: ................ 47 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;The response times that we are seeing, a median of &lt;code&gt;15ms&lt;/code&gt; and p95, p99 of &lt;code&gt;~30ms&lt;/code&gt; and &lt;code&gt;~50ms&lt;/code&gt; respectively, seem like a lot. It's a fairly simple service, it makes sense to expect better. &lt;/p&gt;

&lt;p&gt;We know that we have a performance bottleneck, and apparently this is how it crops up. But we still don't if this is really bad or not, or if we can do better or not and if so then by how much?&lt;/p&gt;




&lt;h3&gt;
  
  
  How to improve?
&lt;/h3&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
We know the bottleneck is that we only have one thread, and if we block it, we are doomed. We need more threads for this. What if we tried &lt;code&gt;worker_threads&lt;/code&gt;? &lt;/p&gt;

&lt;p&gt;Introduced in node 10, these are separate threads with their own eventloops, but they share the same node and v8 instance, unlike child processes. This is what makes&lt;br&gt;
them analogous to standard threads in other runtimes.&lt;/p&gt;

&lt;p&gt;Well, we probably can use them and it might even work, but I wanted to go all in and have a much leaner solution. &lt;/p&gt;

&lt;p&gt;That's why I went with &lt;a href="https://www.rust-lang.org/learn/get-started"&gt;Rust&lt;/a&gt;, to get some near native performance. &lt;/p&gt;


&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegfwgnl1scuhzyp6ifix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegfwgnl1scuhzyp6ifix.png" alt="Image description" width="800" height="1101"&gt;&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
The idea is to use NodeJS for what it's known for, i.e brilliant i/o and async performance, and rust for managing threads. This way we get to have best of both the worlds.&lt;/p&gt;

&lt;p&gt;NodeJS has &lt;code&gt;n-api&lt;/code&gt;/&lt;code&gt;node-api&lt;/code&gt; as a layer which enables FFI(Foreign Function Interface). Essestially, it allows node to call functions running in entirely different runtime, written in some other language.&lt;/p&gt;

&lt;p&gt;Here are the steps involved in this new architecture for our service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NodeJS will still handle the http connection aspect&lt;/li&gt;
&lt;li&gt;On a new request, it will call our rust program to create qr

&lt;ul&gt;
&lt;li&gt;This will be an async call, where our rust program can be viewed like an os/kernel call&lt;/li&gt;
&lt;li&gt;Like registering a callback for event, except the event is that our rust program is ready with qr base64 string.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Once in rust domain, we will parse and clean our input given by NodeJS process&lt;/li&gt;
&lt;li&gt;In rust runtime, we will spawn a new thread

&lt;ul&gt;
&lt;li&gt;We will create a qr for given text where&lt;/li&gt;
&lt;li&gt;Once done, we will intimate that we have a result for the event, and pass it back to NodeJS runtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Once NodeJS knows there's data for the event, it will execute the registered callback with given data.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;The result is that we have simulated qr creation as an os/kernel api which &lt;code&gt;epoll_wait&lt;/code&gt; or equivalent can take care of!&lt;/p&gt;

&lt;p&gt;This is huge because our NodeJS program is now about handling http requests as fast as it can, without worrying about doing something heavy on its main thread.&lt;/p&gt;


&lt;h3&gt;
  
  
  Rust solution
&lt;/h3&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
We are using &lt;a href="https://neon-bindings.com/"&gt;neon&lt;/a&gt; to help us with creating a Rust binding for NodeJS. They have pretty good docs and example for you to start tinkering with it. &lt;/p&gt;

&lt;p&gt;I started with their &lt;a href="https://neon-bindings.com/docs/hello-world"&gt;hello-world&lt;/a&gt; example and then used that as a template.&lt;/p&gt;

&lt;p&gt;Neon creates a node compatible binary, which our NodeJS program then loads as a library and runs. &lt;/p&gt;



&lt;p&gt;Here's the rust code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;neon&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;image&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;DynamicImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ImageOutputFormat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Luma&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;qrcode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;QrCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;neon&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;event&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;create_qr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&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;let&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrcode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;QrCode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="nf"&gt;.as_bytes&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;qrcode_image_buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qrcode&lt;/span&gt;
            &lt;span class="py"&gt;.render&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Luma&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&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="nf"&gt;.max_dimensions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;qrcode_dynamic_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;DynamicImage&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;ImageLuma8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qrcode_image_buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;image_bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qrcode_dynamic_image&lt;/span&gt;&lt;span class="nf"&gt;.write_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;image_bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;ImageOutputFormat&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_bytes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error: Cannot get image bytes"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error: Cannot encode this text"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;create_qr_and_send_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Root&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JsFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_qr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="nf"&gt;.send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="nf"&gt;.into_inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="nf"&gt;.undefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imageString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

                &lt;span class="c1"&gt;// Save the data in a result object.&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="nf"&gt;.empty_object&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="nf"&gt;.string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imageString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="nf"&gt;.set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"imageString"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="nf"&gt;.null&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="py"&gt;.upcast&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JsValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                    &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="nf"&gt;.upcast&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="nf"&gt;.string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
                &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="py"&gt;.upcast&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JsValue&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="p"&gt;};&lt;/span&gt;

        &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="nf"&gt;.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse_js_and_get_qr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FunctionContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;JsResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JsUndefined&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;// The types `String`, `Root&amp;lt;JsFunction&amp;gt;`, and `Channel` can all be&lt;/span&gt;
    &lt;span class="c1"&gt;// sent across threads.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="py"&gt;.argument&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JsString&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="nf"&gt;.value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="py"&gt;.argument&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JsFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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="o"&gt;?&lt;/span&gt;&lt;span class="nf"&gt;.root&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="nf"&gt;.channel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Spawn a background thread to complete the execution. The background&lt;/span&gt;
    &lt;span class="c1"&gt;// execution will _not_ block the JavaScript event loop.&lt;/span&gt;
    &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Do the heavy lifting inside the background thread.&lt;/span&gt;
        &lt;span class="nf"&gt;create_qr_and_send_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="nf"&gt;.undefined&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[neon::main]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ModuleContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;NeonResult&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="n"&gt;cx&lt;/span&gt;&lt;span class="nf"&gt;.export_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"createQR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parse_js_and_get_qr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&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;Here's the js code which uses it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&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;createQR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;util&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;promisify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createQR&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;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;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;QR TEST&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;imageString&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createQR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;imageString&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`App listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;And it works! If we run this code, we will get our base64 representation of a qr code.&lt;/p&gt;

&lt;p&gt;But is it any good? Does this perform better than our main thread blocking version?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─ Custom Metrics ───────────────────────────────────────────┐┌─ Metadata ─────────────────────────────────────────────────────────────────────┐
│ Used Heap Size                                  22.00 MiB  ││ App Name              index                                                    │
│ Heap Usage                                        36.74 %  ││ Namespace             default                                                  │
│ Heap Size                                       59.87 MiB  ││ Version               0.1.0                                                    │
│ Event Loop Latency p95                            2.29 ms  ││ Restarts              0                                                        │
│ Event Loop Latency                                0.17 ms  ││ Uptime                96s                                                      │
│ Active handles                                       1604  ││ Script path           /home/iostreamer/projects/node-rust-hello-world/index.js │
│ Active requests                                         0  ││ Script args           N/A                                                      │
│ HTTP                                       240.11 req/min  ││ Interpreter           node                                                     │
│ HTTP P95 Latency                     9.549999999999955 ms  ││ Interpreter args      N/A                                                      │
│ HTTP Mean Latency                                    1 ms  ││ Exec mode             fork                                                     │
│                                                            ││ Node.js version       16.13.2                                                  │
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--------------------------------
Summary report @ 16:55:55(+0530)
--------------------------------

http.codes.200: .............................50005
http.request_rate: ..........................356/sec
http.requests: ..............................50005
http.response_time:
  min: ......................................0
  max: ......................................58
  median: ...................................1
  p95: ......................................12.1
  p99: ......................................22
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;Important stats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;event-loop-latency:
p95                     2.29 ms
current                 0.17 ms

http.response_time:
  min: ................ 0 ms
  max: ................ 58 ms
  median: ............. 1 ms
  p95: ................ 12.1 ms
  p99: ................ 22 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Comparison
&lt;/h3&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
HTTP performance: Latency in ms&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1tnx6nke15b5jmr9s1q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1tnx6nke15b5jmr9s1q.png" alt="" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Eventloop performance: Latency in ms&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qff97u4tqb944lhc30q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qff97u4tqb944lhc30q.png" alt="" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;&lt;br&gt;&lt;br&gt;
We see a tremendous performance increase, especially in p95 and p99 cases. We successfully modified our app such that not only is it faster on average, but the users facing hiccups aren't far by a huge margin. This ~2-3x increase in performance tells a lot about where node shines and where it shouldn't be used.&lt;/p&gt;

&lt;p&gt;This ability to create native addons has huge implications for JS projects. Imagine you have your entire stack in typescript and all the engineers well versed with TS/JS ecosystem, but you finally hit the limit. Now you can rewrite and retrain, or you can simply create a fast, low surface area library which anyone can plug and play as easily as downloading it from npm.&lt;/p&gt;

&lt;p&gt;All in all, it's looking good for NodeJS with projects like neon and languages like Rust. Given that NodeJS democratized server side development, it has been fascinating to see how the pitfalls have been plugged over the years.&lt;/p&gt;

&lt;p&gt;We now have typescript to instill confidence and now wasm and ffi backed by reliable, safe and blazing fast languages. It's fair to say, NodeJS now has almost everything for everyone.&lt;/p&gt;

</description>
      <category>node</category>
      <category>eventloop</category>
      <category>rust</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Fixing Null Pointer Exceptions with Proxies</title>
      <dc:creator>Rahul Ramteke</dc:creator>
      <pubDate>Sat, 15 Jun 2019 02:02:25 +0000</pubDate>
      <link>https://forem.com/iostreamer/fixing-null-pointer-exceptions-with-proxies-19fc</link>
      <guid>https://forem.com/iostreamer/fixing-null-pointer-exceptions-with-proxies-19fc</guid>
      <description>&lt;p&gt;No more &lt;code&gt;Cannot set property of undefined&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;A proxy, as the name suggests, acts as an interceptor to an object. Every property one accesses, every property one sets, every operation, goes through the proxy.&lt;/p&gt;

&lt;p&gt;Here are some articles to get you to speed on proxies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ponyfoo.com/articles/es6-proxies-in-depth"&gt;https://ponyfoo.com/articles/es6-proxies-in-depth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ponyfoo.com/articles/more-es6-proxy-traps-in-depth"&gt;https://ponyfoo.com/articles/more-es6-proxy-traps-in-depth&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have some idea of using proxies, we can try to solve this problem which came up while implementing a multitenant architecture I was working on.&lt;/p&gt;

&lt;p&gt;Let’s say we have an empty object &lt;code&gt;x = {}&lt;/code&gt; and for some reason we want to do &lt;code&gt;x.y.z = 23;&lt;/code&gt; and not just &lt;code&gt;x.y.z&lt;/code&gt; we want to do add keys and subkeys, infintely to &lt;code&gt;x&lt;/code&gt;. So, &lt;code&gt;x.y.z = 23&lt;/code&gt; and &lt;code&gt;x.y.z.a.i.v.b.n.s = 99&lt;/code&gt; should not throw an error but rather should create the following objects respectively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;99&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="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;Problem is, if we were to do &lt;code&gt;x.y.z = 23&lt;/code&gt; on &lt;code&gt;x = {}&lt;/code&gt;, we’d be trying to access property &lt;code&gt;z&lt;/code&gt; assuming &lt;code&gt;y&lt;/code&gt; exists on &lt;code&gt;x&lt;/code&gt;, but actually it doesn’t, all we have in &lt;code&gt;x&lt;/code&gt; is &lt;code&gt;{}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But what if our &lt;code&gt;x&lt;/code&gt; was smart, so much so, that if we tried to access a property which doesn’t exist, it will create that property on the fly and our code won’t even know!&lt;/p&gt;

&lt;p&gt;What if we intercepted every property access call on &lt;code&gt;x&lt;/code&gt;, checked if the property actually exists, if it doesn’t, initialize it with empty object and then go about our usual business?!&lt;/p&gt;

&lt;p&gt;So, doing &lt;code&gt;x.y.z = 23&lt;/code&gt; will first create &lt;code&gt;y&lt;/code&gt; on &lt;code&gt;x&lt;/code&gt; and then will set &lt;code&gt;z&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And this is where proxies shine, we could do this magic with a simple proxy like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUndefinedHandlerProxy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;undefinedHandlerProxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&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;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;undefinedHandlerProxy&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;The first argument to &lt;code&gt;new Proxy($1, $2)&lt;/code&gt; is basically &lt;code&gt;x&lt;/code&gt;, or the object we want a layer on, the object we want to intercept. The second argument is our handler, a collection of traps and interceptors.&lt;/p&gt;

&lt;p&gt;Here, we decided to intercept property access calls using &lt;code&gt;get&lt;/code&gt; trap. As we planned before, we will check if the property(or key in this case) exists on our object(called target here). This is done using the line &lt;code&gt;if (target[key] === undefined)&lt;/code&gt; and if it doesn’t, we return an empty object, like we planned.&lt;/p&gt;

&lt;p&gt;Let’s see how this helps us solve our problem:&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;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getUndefinedHandlerProxy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our &lt;code&gt;x&lt;/code&gt; is a proxy now, &lt;code&gt;x.y.z&lt;/code&gt; was performed on our proxy, which caught us when we tried to access &lt;code&gt;y&lt;/code&gt;. It checked if &lt;code&gt;y&lt;/code&gt; existed, and since it did not, &lt;code&gt;x.y&lt;/code&gt; returned an empty object, after which, &lt;code&gt;z&lt;/code&gt; was simply set on that returned empty object!&lt;/p&gt;

&lt;p&gt;One little problem though, what if we had &lt;code&gt;x = getUndefinedHandlerProxy();&lt;/code&gt; and did &lt;code&gt;x.y.z.a = 78&lt;/code&gt;? Since &lt;code&gt;x&lt;/code&gt; is proxy, &lt;code&gt;y&lt;/code&gt; would be automatically created as a blank object. But since &lt;code&gt;y&lt;/code&gt; is simple plebian, accessesing &lt;code&gt;y.z.a&lt;/code&gt; would be problematic, as &lt;code&gt;z&lt;/code&gt; doesn’t actually exist, so, we’d be setting &lt;code&gt;a&lt;/code&gt;on &lt;code&gt;undefined&lt;/code&gt;, and now we are back to our original problem. We need &lt;code&gt;y&lt;/code&gt; to be as smart as &lt;code&gt;x&lt;/code&gt; and not a simple object, same goes for all the sub properties that get created. What if &lt;code&gt;y&lt;/code&gt; was actually a proxy, just like &lt;code&gt;x&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;We could do that by changing our proxy a bit, rather than doing &lt;code&gt;target[key] = {}&lt;/code&gt;, we could do&lt;code&gt;target[key] = getUndefinedHandlerProxy()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And now our final code would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUndefinedHandlerProxy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;undefinedHandlerProxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&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;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getUndefinedHandlerProxy&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;undefinedHandlerProxy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this, handles &lt;strong&gt;everything&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One last caveat though, our proxy would always create an object when we try to access a property and it doesn’t exist. Now, what if we wanted to check if a property exists or not, which is a very common scenario in day to day javascript.&lt;/p&gt;

&lt;p&gt;Doing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ourSpecialProxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;ourSpecialProxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Some special code&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;would not work as intended, the condition will &lt;strong&gt;always&lt;/strong&gt; return true.&lt;/p&gt;

&lt;p&gt;One way to avoid this, is not checking property existence directly, we need to check if the property is an actual object/string/number. Or if the property is anything but a proxy.&lt;/p&gt;

&lt;p&gt;For this, we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getActualValueFromUndefinedhandlerProxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&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;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isProxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&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="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&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;It’s a simple function which takes a target and key, if &lt;code&gt;targey[key]&lt;/code&gt; is proxy, then the whole thing is a facade, it returns &lt;code&gt;undefined&lt;/code&gt;. If not, then &lt;code&gt;target[key]&lt;/code&gt; is returned.&lt;/p&gt;

&lt;p&gt;And that’s it, we achieved what we set out to.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;No more &lt;code&gt;Cannot set property of undefined&lt;/code&gt;!&lt;/em&gt;&lt;/p&gt;

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