<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[The Diligent Engineer]]></title><description><![CDATA[The Diligent Engineer]]></description><link>https://thediligentengineer.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1763569113158/20630180-29a5-48af-a729-05a14094e35c.png</url><title>The Diligent Engineer</title><link>https://thediligentengineer.com</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 14 Mar 2026 06:11:04 GMT</lastBuildDate><atom:link href="https://thediligentengineer.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><atom:link rel="first" href="https://thediligentengineer.com/rss.xml"/><atom:link rel="next" href="https://thediligentengineer.com/rss.xml?after=NjU4NjgzNWE2ZGFmMGY1NDdmMTkwMmIyXzIwMjMtMTItMjNUMDY6NTE6MDYuMDYxWg=="/><item><title><![CDATA[Go: When Does Stack Turn Into Heap?]]></title><description><![CDATA[<hr />
<p>In Go, you dont choose stack vs heap.</p>
<p>The compiler does.</p>
<p>Most local variables live on the stack - fast and cheap.<br />But sometimes a value gets promoted to the heap instead.</p>
<p>Why?</p>
<p>Because of <a href="https://go.dev/src/cmd/compile/internal/escape/escape.go"><em><strong>escape analysis</strong></em></a>.</p>
<hr />
<h2>The Classic Example</h2>
<pre><code class="language-go">func foo() *int {
    x := 10
    return &amp;x
}
</code></pre>
<p>At first glance, this looks dangerous.<br />Youre returning a pointer to a local variable.</p>
<p>In C, this is undefined behavior.<br />In Go?</p>
<p>Totally fine.</p>
<p>The compiler sees that <code>x</code> escapes the function scope, so it allocates <code>x</code> on the heap.</p>
<p>Conceptually, it becomes:</p>
<pre><code class="language-go">x := new(int)
*x = 10
return x
</code></pre>
<p>You didnt explicitly ask for heap allocation.<br />But you got one.</p>
<hr />
<h2>What Does Escape Actually Mean?</h2>
<p>A variable escapes when it might outlive the function stack frame.</p>
<p>More precisely: if the compiler cannot prove that a value stays within the current frame, it assumes the value escapes.</p>
<p>Common triggers:</p>
<h3>1 Returning a pointer</h3>
<pre><code class="language-go">return &amp;x
</code></pre>
<p>If the value may outlive the function, it escapes.</p>
<p>Note: returning a pointer does not <em>always</em> force heap allocation.<br />If the compiler can prove, often through inlining, that the value does not actually outlive the caller, it may still keep it on the stack.</p>
<p>Escape analysis is conservative, not naive.</p>
<hr />
<h3>2 Captured by a closure</h3>
<pre><code class="language-go">func foo() func() int {
    x := 10
    return func() int { return x }
}
</code></pre>
<p>The closure may live longer than <code>foo()</code>.<br />If the compiler cannot prove otherwise, <code>x</code> goes to the heap.</p>
<hr />
<h3>3 Used in a goroutine</h3>
<pre><code class="language-go">go func() {
    println(x)
}()
</code></pre>
<p>Now execution is asynchronous.<br />The compiler cannot guarantee that <code>x</code> dies before the goroutine uses it.</p>
<p>Conservatively, heap allocation.</p>
<hr />
<h3>4 Stored inside something that escapes</h3>
<p>If a struct, slice, or interface value escapes, anything it references may escape too.</p>
<p>Escape is transitive.</p>
<hr />
<h2>Important: Escape Analysis Is Conservative</h2>
<p>Gos compiler must be correct.</p>
<p>If it is unsure whether something escapes, it assumes it does.</p>
<p>It would rather allocate on the heap than risk memory unsafety.</p>
<p>That means:</p>
<ul>
<li><p>Escape analysis never makes your program incorrect</p>
</li>
<li><p>But it <em>can</em> make it slower</p>
</li>
</ul>
<hr />
<h2>Why This Is Subtle (Rust Helps Explain ;) )</h2>
<p>In Rust, the equivalent code does not compile:</p>
<pre><code class="language-rust">fn foo() -&gt; &amp;i32 {
    let x = 10;
    &amp;x
}
</code></pre>
<p>Rust forces you to model ownership explicitly.</p>
<p>Go does not.</p>
<p>Instead of rejecting your program, Go changes the allocation strategy behind the scenes.</p>
<p>In Rust, memory rules are visible in the type system.<br />In Go, they live inside the compiler.</p>
<p>You do not see the decision.</p>
<p>Unless you run:</p>
<pre><code class="language-shell">go build -gcflags="-m"
</code></pre>
<p>And then the compiler prints:</p>
<pre><code class="language-plaintext">moved to heap: x
</code></pre>
<hr />
<h2>Because Memory Is Serious Enough, so:</h2>
<p>Go:</p>
<blockquote>
<p>I moved it to the heap for safety.</p>
</blockquote>
<p>You:</p>
<blockquote>
<p>But I didnt ask for that.</p>
</blockquote>
<p>Go:</p>
<blockquote>
<p>Youre welcome.</p>
</blockquote>
<p>🙂</p>
<hr />
<h2>Why You Should Care</h2>
<p>Heap allocations mean:</p>
<ul>
<li><p>More garbage collection</p>
</li>
<li><p>More latency variance</p>
</li>
<li><p>More pressure under load</p>
</li>
</ul>
<p>For most applications, it does not matter.</p>
<p>For high performance systems, it absolutely does.</p>
<p>Understanding when stack turns into heap helps you:</p>
<ul>
<li><p>Reduce allocations</p>
</li>
<li><p>Control GC pressure</p>
</li>
<li><p>Write more predictable code</p>
</li>
<li><p>Interpret <code>-gcflags="-m"</code> output with confidence</p>
</li>
</ul>
<hr />
<h2>So?</h2>
<p>Go gives you simplicity.</p>
<p>That simplicity is powered by a sophisticated compiler performing escape analysis behind the scenes.</p>
<p>Stack vs heap in Go is not a syntax decision.</p>
<p>It is a compiler decision.</p>
<p>And sometimes it decides differently than you expect.</p>
<p>Understanding that boundary is one of the steps from writing Go that works to writing Go that performs.</p>
<p>_</p>
<p>_</p>
<p>_</p>
<p>_</p>
<hr />
<h2>P.S. Why Is This (returing var addr) Undefined Behavior in C? 😉</h2>
<p><em>glad you scroll to this hidden one ;)))</em></p>
<p>In C, this code is undefined behavior:</p>
<pre><code class="language-c">int* foo() {
    int x = 10;
    return &amp;x;  // nah, dangling pointer
}
</code></pre>
<p>Why?</p>
<p>Because <code>x</code> lives on the stack, and its lifetime ends when <code>foo()</code> returns.<br />Returning <code>&amp;x</code> creates a <strong>dangling pointer</strong>  a pointer to memory that is no longer valid.</p>
<p>After the function exits:</p>
<ul>
<li><p>The stack frame is popped</p>
</li>
<li><p>That memory may be reused</p>
</li>
<li><p>The pointer now points to garbage</p>
</li>
</ul>
<p>The C standard does not define what happens if you dereference it. It might:</p>
<ul>
<li><p>Seem to work</p>
</li>
<li><p>Return random data</p>
</li>
<li><p>Crash</p>
</li>
<li><p>Corrupt memory</p>
</li>
<li><p>Break only in release builds</p>
</li>
</ul>
<p>All of those are legal outcomes.</p>
<p>Undefined behavior means the compiler assumes you never do this.<br />So its free to optimize aggressively under that assumption.</p>
<p>Thats why:</p>
<ul>
<li><p>Go silently moves the value to the heap</p>
</li>
<li><p>Rust refuses to compile</p>
</li>
<li><p>C says: You promised you knew what you were doing.</p>
</li>
</ul>
<p>And that promise is where things usually go wrong.</p>
]]></description><link>https://thediligentengineer.com/go-when-does-stack-turn-into-heap</link><guid isPermaLink="true">https://thediligentengineer.com/go-when-does-stack-turn-into-heap</guid><category><![CDATA[memory-management]]></category><category><![CDATA[escape analysis]]></category><category><![CDATA[performance]]></category><category><![CDATA[Rust]]></category><category><![CDATA[C++]]></category><category><![CDATA[C]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[compiler]]></category><category><![CDATA[compilers]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[The Cloudf|are Outage [mDraft]]]></title><description><![CDATA[<p>If you tried to use the internet, or accessing <a target="_blank" href="https://thediligentengineer.com/">thediligentengineer.com</a> on November 18, you probably noticed it was broken. For a solid couple of hours, half the web was throwing 502 errors, loading spinners were spinning into eternity, and 𝕏 (the E's bird) was full of people asking if the apocalypse had started.</p>
<p>Cloudflare released their <a target="_blank" href="https://blog.cloudflare.com/18-november-2025-outage/">post-mortem</a> recently. I read it so you don't have to. It wasn't a super-advanced AI cyber-attack or a guy tripping over a power cord.</p>
<p><em>It was a hardcoded limit and a SQL query.</em></p>
<p>Here is the breakdown of how the internet broke, presented without judgment (mostly).</p>
<h3 id="heading-the-happy-path-is-a-whitelie">The "Happy Path" is a ('white')Lie</h3>
<p>According to the report, the issue started with a "feature file" used by their Bot Management system. This file tells the network how to spot bad bots.</p>
<p>The software reading this file had a memory limit. It was hardcoded to handle a certain amount of data. Then, due to a database issue, the file size doubled.</p>
<p>Instead of saying, "Hey, this file is too big, I'm just going to ignore it and keep the website running," the software decided to do the honorable thing and <strong>crash the entire process</strong>.</p>
<p>It's like burning down your kitchen because your toast got stuck. Sure, the toast is gone, but so is the house.</p>
<h3 id="heading-the-sql-query">The SQL Query</h3>
<p>The root cause was a change in database permissions. Someone decided to make permissions "better" (always a dangerous word).</p>
<p>They had a query running that looked something like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">name</span>, <span class="hljs-keyword">type</span> <span class="hljs-keyword">FROM</span> system.columns <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">table</span> = <span class="hljs-string">'http_requests_features'</span> <span class="hljs-keyword">order</span> <span class="hljs-keyword">by</span> <span class="hljs-keyword">name</span>;
</code></pre>
<p>Notice anything missing? Like, maybe a <code>WHERE database = 'default'</code> clause?</p>
<p>Because they didn't specify <em>which</em> database to look in, and the new permissions allowed the user to see <em>more</em> databases, the query returned duplicate columns. It returned the columns for the default view <em>and</em> the underlying storage.</p>
<p>SQL does exactly what you tell it to do, which is usually the problem. The system assumed, "I will only ever see what I expect to see." The database replied, "Here is everything you asked for," and the application choked on it.</p>
<h3 id="heading-the-is-it-a-ddos-phase">The "Is it a DDoS?" Phase</h3>
<p>My favorite part of the report is the "Fog of War."</p>
<p>When the system started failing, the engineers looked at the graphs. The error rates were fluctuating wildly---up, then down, then up again.</p>
<p>Why? because the bad config file was being generated every 5 minutes. Depending on which database shard the query hit, it would either generate a good file (recovery!) or a bad file (crash!).</p>
<p>Because of this weird pattern, the team naturally assumed: <strong>"We are under attack."</strong></p>
<p>They thought it was a massive DDoS. At the same time, the Cloudflare Status Page went down. This turned out to be a total coincidence, hosted on a completely different infrastructure. But imagine being in that war room: The network is crashing, the graphs look crazy, and even your Status Page is dead. You'd probably start looking out the window for alien spaceships.</p>
<h3 id="heading-the-fix">The Fix</h3>
<p>Once they realized it wasn't hackers, but their own code checking out early, the fix was simple:</p>
<ol>
<li><p>Stop generating the bad file.</p>
</li>
<li><p>Put the old, good file back.</p>
</li>
<li><p>Restart the thing.</p>
</li>
</ol>
<p>It's the enterprise version of "Have you tried turning it off and on again?"</p>
<h3 id="heading-the-internet-blames-rust-naturally">The Internet Blames Rust (Naturally)</h3>
<p>Cloudflare is famous for loving the Rust programming language because it is mem safe.</p>
<p>Naturally, as soon as the outage happened, everyone on Hacker News and Reddit glanced at the headline, saw "limit exceeded," and immediately decided the entire Cloudflare codebase must look exactly like this single line of code:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">load_global_config</span></span>() {
    <span class="hljs-comment">// We expect the file to be small.</span>
    <span class="hljs-comment">// We are seemingly 100% sure it will be small.</span>
    <span class="hljs-comment">// So we use the "Trust Me Bro" function:</span>

    <span class="hljs-keyword">let</span> safe_config = download_features()
        .fit_into_memory_limit()
        .unwrap(); <span class="hljs-comment">// &lt;--- The exact moment the internet died</span>
}
</code></pre>
<p>It's cutesy. We love to blame <code>.unwrap()</code> because it's the developer saying, "I promise this value will never be an error." And on November 18, the database looked at that promise and said, "Bet."</p>
<p>Technically, the code <em>was</em> safe. It safely exited the building... it just took all our traffic with it. 😉</p>
<h3 id="heading-the-verdict">The Verdict</h3>
<p>Cloudflare is great, and their transparency is gold standard. But this is a gentle reminder to all of us who write code:</p>
<ul>
<li><p><strong>Validate your inputs</strong>, even if they come from inside the house.</p>
</li>
<li><p><strong>Be explicit in SQL</strong>, because databases love to be technically correct but practically destructive.</p>
</li>
<li><p><strong>Don't hardcode limits</strong> that crash the main thread if exceeded. Just log an error. We promise we'll read the logs eventually. Maybe.</p>
</li>
</ul>
<p>The internet is a fragile ecosystem held together by duct tape and <code>SELECT *</code> statements. Stay safe out there.</p>
]]></description><link>https://thediligentengineer.com/the-cloudfare-outage-mdraft</link><guid isPermaLink="true">https://thediligentengineer.com/the-cloudfare-outage-mdraft</guid><category><![CDATA[memes]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[The Redlock Algorithm]]></title><description><![CDATA[<p>The Redlock algorithm is a distributed locking mechanism designed for Redis to ensure mutual exclusion across clients in a distributed system. It operates by acquiring locks on a majority of Redis nodes to guard against node failures and network partitions. Despite its popularity, Redlock has sparked debate regarding its safety guarantees and implementation complexity.</p>
<h2 id="heading-distributed-locks">Distributed locks</h2>
<p>Distributed locks are crucial for coordinating access to shared resources in distributed applications. Traditional locking mechanisms often rely on a central coordinator, which can become a single point of failure. Redlock offers a decentralized approach by leveraging multiple independent Redis instances.</p>
<h2 id="heading-how-redlock-works">How Redlock Works</h2>
<p>To acquire a lock, a client generates a unique token and sends a <code>SET key value NX PX ttl</code> command to each of the N Redis instances. The client considers the lock acquired only if it successfully locks a majority (quorum) of the instances. The total time to acquire the lock must be less than the TTL specified to prevent expired locks from being mistaken as held. When the client completes its critical section, it releases the lock by sending a <code>DEL key</code> command to all instancesbut only if the stored token matchesto prevent releasing someone elses lock.</p>
<h2 id="heading-algorithm">Algorithm</h2>
<ol>
<li><strong>Acquire</strong>: The client tries to acquire the lock on each instance sequentially with a unique identifier and expiration time.  </li>
<li><strong>Validate</strong>: It computes the elapsed time and verifies if the quorum was achieved within the TTL to ensure lock validity.  </li>
<li><strong>Commit/Abort</strong>: If the quorum is met and the timing constraints hold, the client holds the lock; otherwise, it rolls back by deleting partial locks from the instances.</li>
</ol>
<pre><code class="lang-mermaid">sequenceDiagram
    participant Client
    participant Redis1
    participant Redis2
    participant Redis3
    participant Redis4
    participant Redis5

    Note over Client: Step 1: Generate unique lock ID &amp; start timer

    Client-&gt;&gt;Redis1: SET resource_name lock_id NX PX 3000
    Client-&gt;&gt;Redis2: SET resource_name lock_id NX PX 3000
    Client-&gt;&gt;Redis3: SET resource_name lock_id NX PX 3000
    Client-&gt;&gt;Redis4: SET resource_name lock_id NX PX 3000
    Client-&gt;&gt;Redis5: SET resource_name lock_id NX PX 3000

    Note over Client: Step 2: Wait for quorum (e.g., 3/5 successes)

    alt Quorum Achieved within timeout
        Note over Client: Step 3: Lock acquired
    else Quorum NOT achieved
        Note over Client: Step 3: Roll back&lt;br/&gt;delete partial locks
        Client-&gt;&gt;Redis1: DEL resource_name (if lock_id matches)
        Client-&gt;&gt;Redis2: DEL resource_name (if lock_id matches)
        Client-&gt;&gt;Redis3: DEL resource_name (if lock_id matches)
        Client-&gt;&gt;Redis4: DEL resource_name (if lock_id matches)
        Client-&gt;&gt;Redis5: DEL resource_name (if lock_id matches)
    end

    Note over Client: Step 4: Perform work under lock

    Note over Client: Step 5: Release lock
    Client-&gt;&gt;Redis1: DEL resource_name (if lock_id matches)
    Client-&gt;&gt;Redis2: DEL resource_name (if lock_id matches)
    Client-&gt;&gt;Redis3: DEL resource_name (if lock_id matches)
    Client-&gt;&gt;Redis4: DEL resource_name (if lock_id matches)
    Client-&gt;&gt;Redis5: DEL resource_name (if lock_id matches)
</code></pre>
<h2 id="heading-it-seems-like-twophase-commit">It seems like TwoPhase Commit?</h2>
<p>Redlock resembles a twophase commit in that it performs a prepare phase (acquiring locks) followed by a commit or abort (keeping or releasing locks) based on quorum success. Unlike traditional 2PC, Redlock does not rely on a central coordinator and can tolerate some instance failures without blocking the system.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>Redlock</td><td>2PC</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Quorum vs All-or-Nothing</strong></td><td>Redlock tolerates partial failure (just needs majority)</td><td>2PC requires full agreement</td></tr>
<tr>
<td><strong>Coordinator role</strong></td><td>No formal coordinator; the client drives the logic</td><td>Central coordinator (e.g., transaction manager)</td></tr>
<tr>
<td><strong>Durability guarantees</strong></td><td>Redis isn't strongly consistent</td><td>2PC assumes stronger consistency and logging</td></tr>
<tr>
<td><strong>Failure tolerance</strong></td><td>More optimistic, faster (but less safe in edge cases)</td><td>More rigid but safer in distributed systems</td></tr>
</tbody>
</table>
</div><h2 id="heading-pros-and-cons">Pros and Cons</h2>
<p><strong>Pros</strong>  </p>
<ul>
<li>Provides fault tolerance by ensuring locks remain valid even if some Redis nodes fail.  </li>
<li>Uses TTLs to prevent deadlocks by automatically expiring locks if clients crash before releasing them.  </li>
</ul>
<p><strong>Cons</strong>  </p>
<ul>
<li>Requires careful coordination of multiple Redis instances, increasing operational complexity.  </li>
<li>May not guarantee mutual exclusion under certain failure scenarios, like network partitions during replication.</li>
</ul>
<h2 id="heading-best-practices">Best Practices</h2>
<p>Operators should deploy an odd number of independent Redis masters with synchronized clocks to minimize TTL drift. Clients should handle lock acquisition failures gracefully by implementing retry logic with exponential backoff to avoid thundering herd problems.</p>
<h2 id="heading-implementations">Implementations</h2>
<p>According to <a target="_blank" href="https://redis.io/docs/latest/develop/use/patterns/distributed-locks/">redis</a>:</p>
<ul>
<li><a target="_blank" href="https://github.com/antirez/redlock-rb">Redlock-rb</a> (Ruby implementation). There is also a <a target="_blank" href="https://github.com/leandromoreira/redlock-rb">fork of Redlock-rb</a> that adds a gem for easy distribution.</li>
<li><a target="_blank" href="https://github.com/0exp/redis_queued_locks">RedisQueuedLocks</a> (Ruby implementation).</li>
<li><a target="_blank" href="https://github.com/SPSCommerce/redlock-py">Redlock-py</a> (Python implementation).</li>
<li><a target="_blank" href="https://github.com/brainix/pottery#redlock">Pottery</a> (Python implementation).</li>
<li><a target="_blank" href="https://github.com/joanvila/aioredlock">Aioredlock</a> (Asyncio Python implementation).</li>
<li><a target="_blank" href="https://github.com/malkusch/lock#redismutex">RedisMutex</a> (PHP implementation with both <a target="_blank" href="https://github.com/phpredis/phpredis">Redis extension</a> and <a target="_blank" href="https://github.com/predis/predis">Predis library</a> clients support).</li>
<li><a target="_blank" href="https://github.com/ronnylt/redlock-php">Redlock-php</a> (PHP implementation).</li>
<li><a target="_blank" href="https://github.com/cheprasov/php-redis-lock">cheprasov/php-redis-lock</a> (PHP library for locks).</li>
<li><a target="_blank" href="https://github.com/rtckit/reactphp-redlock">rtckit/react-redlock</a> (Async PHP implementation).</li>
<li><a target="_blank" href="https://github.com/go-redsync/redsync">Redsync</a> (Go implementation).</li>
<li><a target="_blank" href="https://github.com/mrniko/redisson">Redisson</a> (Java implementation).</li>
<li><a target="_blank" href="https://github.com/sbertrang/redis-distlock">Redis::DistLock</a> (Perl implementation).</li>
<li><a target="_blank" href="https://github.com/jacket-code/redlock-cpp">Redlock-cpp</a> (C++ implementation).</li>
<li><a target="_blank" href="https://github.com/sewenew/redis-plus-plus/#redlock">Redis-plus-plus</a> (C++ implementation).</li>
<li><a target="_blank" href="https://github.com/kidfashion/redlock-cs">Redlock-cs</a> (C#/.NET implementation).</li>
<li><a target="_blank" href="https://github.com/samcook/RedLock.net">RedLock.net</a> (C#/.NET implementation). Includes async and lock extension support.</li>
<li><a target="_blank" href="https://github.com/psibernetic/scarletlock">ScarletLock</a> (C# .NET implementation with configurable datastore).</li>
<li><a target="_blank" href="https://github.com/LiZhenNet/Redlock4Net">Redlock4Net</a> (C# .NET implementation).</li>
<li><a target="_blank" href="https://github.com/mike-marcacci/node-redlock">node-redlock</a> (NodeJS implementation). Includes support for lock extension.</li>
<li><a target="_blank" href="https://github.com/oslabs-beta/Deno-Redlock">Deno DLM</a> (Deno implementation)</li>
<li><a target="_blank" href="https://github.com/hexcowboy/rslock">Rslock</a> (Rust implementation). Includes async and lock extension support.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Redlock remains a valuable tool for distributed locking in Redis when used with care and understanding of its tradeoffs. By following best practices and acknowledging its limitations, teams can leverage Redlock to maintain data consistency in distributed systems.</p>
<h2 id="heading-references">References</h2>
<ol>
<li><a target="_blank" href="https://redis.io/docs/latest/develop/use/patterns/distributed-locks/">Distributed Locks with Redis | Redis Docs</a>  </li>
<li><a target="_blank" href="https://redis.io/glossary/redis-lock/">Redis Lock  Redlock Algorithm | Redis Glossary</a> </li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Distributed_lock_manager">Distributed lock manager  Wikipedia</a>  </li>
</ol>
]]></description><link>https://thediligentengineer.com/the-redlock-algorithm</link><guid isPermaLink="true">https://thediligentengineer.com/the-redlock-algorithm</guid><category><![CDATA[redlock]]></category><category><![CDATA[Redis]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[distributed system]]></category><category><![CDATA[distributed-transactions]]></category><category><![CDATA[algorithms]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Writing SQL in Big Data System]]></title><description><![CDATA[<p>Working with massive datasets changes how you approach writing SQL. Its not just about writing correct queries  its about writing <em>smart</em> ones that respect scale, cost, and the distributed nature of the underlying systems. Here are some hard-earned lessons and best practices from my journey wrangling SQL in big data environments like Hive, Presto, BigQuery, and Spark SQL.</p>
<hr />
<h2 id="heading-1-push-work-down-let-the-engine-work-for-you">1. <strong>Push Work Down  Let the Engine Work for You</strong></h2>
<p>In distributed systems, each stage of the query execution plan (especially filters and projections) matters. The golden rule:</p>
<blockquote>
<p><strong>Always filter early, project only what you need.</strong></p>
</blockquote>
<p>By reducing the amount of data read and shuffled, you cut down IO, memory usage, and execution time significantly. For example:</p>
<pre><code class="lang-sql"><span class="hljs-comment">-- Avoid</span>
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">events</span> <span class="hljs-keyword">WHERE</span> event_type = <span class="hljs-string">'purchase'</span>;

<span class="hljs-comment">-- Prefer</span>
<span class="hljs-keyword">SELECT</span> user_id, event_time <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">events</span> <span class="hljs-keyword">WHERE</span> event_type = <span class="hljs-string">'purchase'</span>;
</code></pre>
<hr />
<h2 id="heading-2-understand-partitioning-and-bucketing">2. <strong>Understand Partitioning and Bucketing</strong></h2>
<p>Big data systems usually partition tables to improve query performance. If you ignore partitioning, you're likely scanning terabytes unnecessarily.</p>
<blockquote>
<p>Know your tables partition columns  and <strong>use them in WHERE clauses</strong>.</p>
</blockquote>
<pre><code class="lang-sql"><span class="hljs-comment">-- Leverage partition pruning</span>
<span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">COUNT</span>(*) 
<span class="hljs-keyword">FROM</span> <span class="hljs-keyword">logs</span> 
<span class="hljs-keyword">WHERE</span> event_date = <span class="hljs-string">'2025-04-15'</span>;
</code></pre>
<p>If you're designing tables, partition on columns with high cardinality and frequent filtering. Avoid over-partitioning (e.g., hourly), which leads to small files and metadata overhead.</p>
<hr />
<h2 id="heading-3-watch-for-data-skew">3. <strong>Watch for Data Skew</strong></h2>
<p>One sneaky performance killer is skewed data  where a few values dominate a join or group by. This causes uneven workload distribution, leaving some workers idle while others are overloaded.</p>
<p><strong>Telltale signs:</strong></p>
<ul>
<li>Stages stuck at 99% for a long time.</li>
<li>Huge temp spill files on specific workers.</li>
</ul>
<h3 id="heading-how-to-mitigate">How to mitigate:</h3>
<ul>
<li><strong>Salting keys</strong> (add a random suffix to break hotspots).</li>
<li>Use approximate aggregations where precision isn't mission-critical.</li>
<li>Rewrite joins as map-side when appropriate.</li>
</ul>
<hr />
<h2 id="heading-4-avoid-cross-joins-and-cartesian-products">4. <strong>Avoid Cross Joins and Cartesian Products</strong></h2>
<p>It seems obvious, but in massive datasets, even an accidental cross join can generate <em>petabytes</em> of intermediate data. Be explicit in join conditions and cautious with one-to-many relationships.</p>
<pre><code class="lang-sql"><span class="hljs-comment">-- Danger zone</span>
<span class="hljs-keyword">SELECT</span> a.*, b.* 
<span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> a, <span class="hljs-keyword">events</span> b 
<span class="hljs-keyword">WHERE</span> a.user_id = b.user_id;  <span class="hljs-comment">-- missing JOIN syntax is risky</span>

<span class="hljs-comment">-- Safer</span>
<span class="hljs-keyword">SELECT</span> a.*, b.*
<span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> a
<span class="hljs-keyword">JOIN</span> <span class="hljs-keyword">events</span> b <span class="hljs-keyword">ON</span> a.user_id = b.user_id;
</code></pre>
<hr />
<h2 id="heading-5-use-with-clauses-and-ctes-judiciously">5. <strong>Use WITH Clauses and CTEs Judiciously</strong></h2>
<p>CTEs (Common Table Expressions) improve readability, but <strong>some engines materialize them</strong>, which can result in recomputation. For frequently reused logic or expensive computations, <strong>cache results or persist to a temp table</strong>.</p>
<pre><code class="lang-sql"><span class="hljs-comment">-- Avoid repeating subqueries in massive datasets</span>
<span class="hljs-keyword">WITH</span> filtered <span class="hljs-keyword">AS</span> (
  <span class="hljs-keyword">SELECT</span> user_id, <span class="hljs-keyword">SUM</span>(amount) <span class="hljs-keyword">AS</span> total_spent
  <span class="hljs-keyword">FROM</span> transactions
  <span class="hljs-keyword">WHERE</span> event_date &gt;= <span class="hljs-string">'2025-01-01'</span>
  <span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> user_id
)
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> filtered <span class="hljs-keyword">WHERE</span> total_spent &gt; <span class="hljs-number">1000</span>;
</code></pre>
<hr />
<h2 id="heading-6-understand-cost-models-and-query-plans">6. <strong>Understand Cost Models and Query Plans</strong></h2>
<p>A habit worth cultivating: <strong>always inspect the execution plan</strong>. Use <code>EXPLAIN</code> or visual tools to:</p>
<ul>
<li>Spot full scans</li>
<li>Understand join order</li>
<li>Check shuffle/sort stages</li>
</ul>
<p>This is especially critical in systems like Spark or Presto where optimizers can make suboptimal decisions.</p>
<blockquote>
<p>💡 Pro Tip: </p>
<p>In BigQuery, filter on partitioned and clustered columns to benefit from partition pruning and block elimination.</p>
</blockquote>
<hr />
<h2 id="heading-7-beware-of-wide-joins-and-explosions">7. <strong>Beware of Wide Joins and Explosions</strong></h2>
<p>Be mindful of fan-out joins, especially when joining arrays or struct types that can cause row multiplication.</p>
<blockquote>
<p>If youre joining nested fields, <strong>flatten responsibly</strong>.</p>
</blockquote>
<p>In systems like Spark SQL:</p>
<ul>
<li>Use <code>explode()</code> with care.</li>
<li>Always check the row count before and after to detect accidental data amplification.</li>
</ul>
<hr />
<h2 id="heading-8-monitor-query-cost-and-audit-usage">8. <strong>Monitor Query Cost and Audit Usage</strong></h2>
<p>In systems like BigQuery or Athena, you pay by data scanned. Even a simple <code>SELECT COUNT(*) FROM table</code> can cost dollars if you don't project partitions or filter early.</p>
<p>Set up dashboards:</p>
<ul>
<li>Query cost by user or team</li>
<li>Top tables by scan volume</li>
<li>Longest running queries</li>
</ul>
<p>Cost-awareness = performance discipline.</p>
<hr />
<h2 id="heading-9-materialize-strategic-results">9. <strong>Materialize Strategic Results</strong></h2>
<p>Instead of chaining many heavy transformations, <strong>break your pipeline</strong>:</p>
<ul>
<li>Materialize intermediate results (to a temp or summary table).</li>
<li>Validate, then continue downstream.</li>
</ul>
<p>This helps with reusability, debuggability, and disaster recovery.</p>
<hr />
<h2 id="heading-10-automate-linting-and-review-of-sql">10. <strong>Automate Linting and Review of SQL</strong></h2>
<p>Treat SQL as production code. Use tools that lint SQL for anti-patterns (e.g., full scans, cross joins) or enforce style consistency in your team.</p>
<p>For example:</p>
<ul>
<li><strong>SQLFluff</strong> for syntax/style</li>
<li><strong>Datafold or dbt</strong> for CI/CD with data quality checks</li>
</ul>
<hr />
<h1 id="heading-final-thoughts">Final Thoughts</h1>
<p>Working with SQL in big data is like driving a race car  you're dealing with speed, power, and risk. The key is to <strong>design queries that respect scale</strong>, understand the engine underneath, and develop a culture of experimentation and observability.</p>
<p>The faster you get at reading query plans, the faster you become at writing efficient SQL.</p>
<p>If youre just starting out, pick one of these lessons and apply it to a real query  youll be surprised how far a small change can go at scale.</p>
]]></description><link>https://thediligentengineer.com/writing-sql-in-big-data-system</link><guid isPermaLink="true">https://thediligentengineer.com/writing-sql-in-big-data-system</guid><category><![CDATA[SQL]]></category><category><![CDATA[big data]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Effect?]]></title><description><![CDATA[<p>I've been working with TypeScript for years, and I've always been seeking better ways to handle side effects, errors, and dependencies. When I discovered Effect, it changed my approach to functional programming completely.</p>
<h2 id="heading-what-effect-really-is">What Effect Really Is</h2>
<p><a target="_blank" href="https://effect.website/">Effect</a> isn't just another TypeScript library. As Ethan Niser explains in his <a target="_blank" href="https://ethanniser.dev/blog/the-truth-about-effect/">insightful article</a>:</p>
<blockquote>
<p><strong>Effect is a language.</strong></p>
<p>Specifically, Effect is an attempt to answer a question that many people have asked, and a few have answered: what would it look like if we had a language for describing effectful computations?</p>
</blockquote>
<p>This realization hit me when I was reimagining a GitHub followers tracking tool. Effect isn't merely a collection of utility functionsit's a comprehensive approach to handling effectful computations within TypeScript.</p>
<p>What makes Effect special is how it extends existing tools:</p>
<ul>
<li>It extends <code>Promise</code> by making laziness, error handling, retries, interruption, and observability first-class citizens</li>
<li>It extends TypeScript by adding typed errors, typed dependency injection, and structured concurrency</li>
<li>It provides a rich standard library while making effects a language primitive</li>
</ul>
<p>Let me show you the contrast between traditional Promise approaches and Effect:</p>
<pre><code class="lang-mermaid">flowchart LR
    subgraph "Traditional Promise Approach"
    A[Call API] --&gt; B{Success?}
    B --&gt;|Yes| C[Process Data]
    B --&gt;|No| D[Catch Error]
    D --&gt; E[Log or Rethrow]
    end

    subgraph "Effect Approach"
    F[Define Effect] --&gt; G[Compose with other Effects]
    G --&gt; H[Handle all errors]
    H --&gt; I[Inject dependencies]
    I --&gt; J[Run the Effect]
    end

    style F fill:#d4f1f9
    style G fill:#d4f1f9
    style H fill:#d4f1f9
    style I fill:#d4f1f9
    style J fill:#d4f1f9
</code></pre>
<p>With traditional Promises, error handling is bolted on with <code>.catch()</code>. With Effect, errors are part of the type signature itself - you simply can't forget to handle them.</p>
<h2 id="heading-the-tradeoffs-of-effect">The Tradeoffs of Effect</h2>
<p>Before diving into my implementation, I should note that Effect isn't without its tradeoffs:</p>
<ol>
<li><strong>Learning curve</strong> - Despite being more approachable than pure FP libraries, there's still a learning curve, especially for teams unfamiliar with functional concepts</li>
<li><strong>Bundle size</strong> - At 14KB minified+gzipped (core), it's lightweight but not free</li>
<li><strong>Ecosystem maturity</strong> - While growing rapidly, the ecosystem isn't as extensive as more established libraries</li>
<li><strong>Debug experience</strong> - Stack traces can sometimes be harder to interpret due to the generator-based implementation</li>
</ol>
<p>Despite these considerations, for many applications, the benefits significantly outweigh these costs.</p>
<h2 id="heading-play-with-effect">Play with Effect</h2>
<p>To test these ideas of this new programming language, I took an existing tool<a target="_blank" href="https://github.com/tuananh/github-followers-watch">GitHub Followers Watch</a> originally written in Goand reimplemented it as <a target="_blank" href="https://github.com/lyluongthien/github-watcher">GitHub Watcher</a> using TypeScript and Effect.</p>
<p>The original tool's purpose was simple: track GitHub followers and following lists to monitor changes over time. But rebuilding it with Effect demonstrated some powerful concepts:</p>
<pre><code class="lang-mermaid">flowchart TD
    A[GitHub API] --&gt; B[GitHub API Layer]
    B --&gt; C[Effect Program]
    C --&gt; D{Command Line Interface}
    D --&gt; E[List Followers Command]
    D --&gt; F[List Following Command]
    E --&gt; G[Output to Console/File]
    F --&gt; G
    H[Environment Variables] --&gt; B
</code></pre>
<h3 id="heading-typed-errors-no-more-trycatch-chaos">Typed Errors: No More Try/Catch Chaos</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> GitHubApiError <span class="hljs-keyword">extends</span> <span class="hljs-built_in">Error</span> {
  <span class="hljs-keyword">readonly</span> _tag = <span class="hljs-string">"GitHubApiError"</span>;
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">message: <span class="hljs-built_in">string</span></span>) {
    <span class="hljs-built_in">super</span>(message);
    <span class="hljs-built_in">this</span>.name = <span class="hljs-string">"GitHubApiError"</span>;
  }
}
</code></pre>
<p>This isn't just error handlingit's precise, typed error handling that lets you know exactly what can fail at compile time.</p>
<h3 id="heading-describing-effects-with-types">Describing Effects With Types</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> GitHubApi {
  <span class="hljs-keyword">readonly</span> getSelfID: Effect.Effect&lt;<span class="hljs-built_in">string</span>, GitHubApiError&gt;;
  <span class="hljs-keyword">readonly</span> listAllFollowing: <span class="hljs-function">(<span class="hljs-params">username: <span class="hljs-built_in">string</span></span>) =&gt;</span> Effect.Effect&lt;<span class="hljs-built_in">string</span>[], GitHubApiError&gt;;
  <span class="hljs-keyword">readonly</span> listAllFollowers: <span class="hljs-function">(<span class="hljs-params">username: <span class="hljs-built_in">string</span></span>) =&gt;</span> Effect.Effect&lt;<span class="hljs-built_in">string</span>[], GitHubApiError&gt;;
}
</code></pre>
<p>Look at that interface. The return type tells you everything: what the success value is, what can go wrong, and what dependencies it hasall in one unified type.</p>
<p>Here's how Effect's type signature compares to other approaches:</p>
<pre><code class="lang-mermaid">classDiagram
    class Promise {
        +then(success)
        +catch(error)
        -No typed errors
        -No dependency tracking
    }

    class Either {
        +map(f)
        +flatMap(f)
        +Typed errors
        -Eager evaluation
        -No dependency tracking
    }

    class Effect {
        +map(f)
        +flatMap(f)
        +provide(dependencies)
        +Typed errors
        +Dependency tracking
        +Resource management
        +Lazy evaluation
        +Structured concurrency
    }
</code></pre>
<h3 id="heading-generator-based-composition-readable-async-code">Generator-Based Composition: Readable Async Code</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> printFollowers = Effect.gen(<span class="hljs-function"><span class="hljs-keyword">function</span>* (<span class="hljs-params">_</span>) </span>{
  <span class="hljs-keyword">const</span> api = <span class="hljs-keyword">yield</span>* _(Effect.map(GitHubApiLive, <span class="hljs-function"><span class="hljs-params">layer</span> =&gt;</span> layer.GitHubApi));
  <span class="hljs-keyword">const</span> login = <span class="hljs-keyword">yield</span>* _(api.getSelfID);
  <span class="hljs-keyword">const</span> followers = <span class="hljs-keyword">yield</span>* _(api.listAllFollowers(login));
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">yield</span>* _(Console.log(<span class="hljs-string">`<span class="hljs-subst">${followers.join(<span class="hljs-string">"\n"</span>)}</span>`</span>));
});
</code></pre>
<p>This is where Effect shines. The generator syntax makes asynchronous code read like synchronous code, but without losing precise error handling or types.</p>
<h3 id="heading-dependency-injection-without-the-framework">Dependency Injection Without the Framework</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> GitHubApiLive = Effect.gen(<span class="hljs-function"><span class="hljs-keyword">function</span>* (<span class="hljs-params">_</span>) </span>{
  <span class="hljs-keyword">const</span> token = <span class="hljs-keyword">yield</span>* _(Effect.try({
    <span class="hljs-keyword">try</span>: <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">const</span> token = process.env.PERSONAL_ACCESS_TOKEN;
      <span class="hljs-keyword">if</span> (!token) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"PERSONAL_ACCESS_TOKEN env var not set"</span>);
      <span class="hljs-keyword">return</span> token;
    },
    <span class="hljs-keyword">catch</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">new</span> GitHubApiError(<span class="hljs-string">"PERSONAL_ACCESS_TOKEN env var not set"</span>)
  }));

  <span class="hljs-keyword">const</span> octokit = <span class="hljs-keyword">new</span> Octokit({ auth: token });
  <span class="hljs-keyword">return</span> makeGitHubApi(octokit);
}).pipe(Effect.map(<span class="hljs-function"><span class="hljs-params">api</span> =&gt;</span> ({ GitHubApi: api })));
</code></pre>
<p>Dependencies are handled through layers, not some complicated DI container. It's just values all the way down.</p>
<p>Here's a visualization of Effect's dependency injection approach:</p>
<pre><code class="lang-mermaid">flowchart TD
    subgraph "Application"
    A[Main Effect] --&gt; B[Service 1]
    A --&gt; C[Service 2]
    B --&gt; D[Service 3]
    end

    subgraph "Configuration"
    E[Live Implementation] --&gt; F[Config 1]
    E --&gt; G[Config 2]
    end

    subgraph "Runtime"
    H[Provide Layer] --&gt; A
    E --&gt; H
    end

    style A fill:#f9d6d2
    style B fill:#f9d6d2
    style C fill:#f9d6d2
    style D fill:#f9d6d2
    style E fill:#d2f9d6
    style F fill:#d2f9d6
    style G fill:#d2f9d6
    style H fill:#d6d2f9
</code></pre>
<h2 id="heading-testing-the-killer-feature">Testing: The Killer Feature</h2>
<p>The biggest "aha" moment came when testing. With <code>@effect/vitest</code>, testing effectful code becomes almost trivial:</p>
<pre><code class="lang-typescript">it.effect(<span class="hljs-string">"fetches and prints followers"</span>, <span class="hljs-function">() =&gt;</span>
  Effect.gen(<span class="hljs-function"><span class="hljs-keyword">function</span>* (<span class="hljs-params">_</span>) </span>{
    <span class="hljs-keyword">const</span> consoleLogSpy = vi.spyOn(<span class="hljs-built_in">console</span>, <span class="hljs-string">"log"</span>).mockImplementation(<span class="hljs-function">() =&gt;</span> {})

    <span class="hljs-built_in">console</span>.log(mockFollowers.join(<span class="hljs-string">"\n"</span>))

    <span class="hljs-keyword">try</span> {
      assert.strictEqual(consoleLogSpy.mock.calls.length, <span class="hljs-number">1</span>)
      assert.strictEqual(consoleLogSpy.mock.calls[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>], mockFollowers.join(<span class="hljs-string">"\n"</span>))
    } <span class="hljs-keyword">finally</span> {
      consoleLogSpy.mockRestore()
    }
  })
)
</code></pre>
<h2 id="heading-when-not-to-use-effect">When Not to Use Effect</h2>
<p>While I'm enthusiastic about Effect, it's not the right solution for every problem:</p>
<ol>
<li><strong>Small, simple utilities</strong> - For tiny scripts or utilities, Effect might be overkill</li>
<li><strong>Performance-critical hot paths</strong> - For code that needs absolute maximum performance, the abstractions might introduce overhead</li>
<li><strong>Teams unfamiliar with FP</strong> - If your team has no experience with functional concepts, the learning curve might outweigh the benefits initially</li>
<li><strong>Very small microservices</strong> - For extremely focused microservices, the complexity might not be justified</li>
</ol>
<h2 id="heading-the-revelation">The Revelation</h2>
<p>Here's what I've realized: Effect isn't trying to replace TypeScript or make you learn a completely new language. It's extending what you already know by making effectful computations a first-class concept.</p>
<p>You don't need to discard your years of experience with JavaScript, TypeScript, and Node. Effect builds on them by using standard language features:</p>
<ul>
<li>Generators for composition</li>
<li>TypeScript's type system for tracking success, errors, and dependencies</li>
<li>An ecosystem of modules that work together seamlessly</li>
</ul>
<p>This is what Ethan meant when he called Effect a languageit's a way of expressing computations within TypeScript that gives you superpowers without forcing you to abandon your existing knowledge.</p>
<pre><code class="lang-mermaid">graph TD
    A[TypeScript] --&gt; B[Effect]
    C[JavaScript] --&gt; A
    D[Node.js] --&gt; E[Effect Platforms]
    B --&gt; F[Your Application]
    E --&gt; F

    style A fill:#f9d6d2
    style B fill:#d2f9d6
    style C fill:#f9d6d2
    style D fill:#f9d6d2
    style E fill:#d2f9d6
    style F fill:#d6d2f9
</code></pre>
<h2 id="heading-try-it-yourself">Try It Yourself</h2>
<p>Whether you're building a tiny utility or a complex application, Effect provides a functional approach without the learning curve normally associated with purely functional languages.</p>
<p>Give it a try in your next project. You might find yourself thinking of TypeScript in a completely different wayI know I did.</p>
<h2 id="heading-resources">Resources</h2>
<ul>
<li><a target="_blank" href="https://effect.website/">Effect Official Website</a></li>
<li><a target="_blank" href="https://github.com/lyluongthien/github-watcher">GitHub Watcher</a></li>
<li><a target="_blank" href="https://ethanniser.dev/blog/the-truth-about-effect/">The Truth About Effect by Ethan Niser</a></li>
</ul>
]]></description><link>https://thediligentengineer.com/effect</link><guid isPermaLink="true">https://thediligentengineer.com/effect</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[fault tolerance]]></category><category><![CDATA[error handling]]></category><category><![CDATA[effect]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Leopard - the c⁽¹⁾ of O(1) Indexing System]]></title><description><![CDATA[<h3 id="heading-what-is-leopard"><strong>What is</strong> <strong>Leopard?</strong></h3>
<blockquote>
<p>The leopard is one of the five extant cat species in the genus Panthera. It has a pale yellowish to dark golden fur with dark spots grouped in rosettes. Its body is slender and muscular reaching a length of 92183 cm with a 66102 cm long tail and a shoulder height of 6070 cm. <a target="_blank" href="https://en.wikipedia.org/wiki/Leopard">Wikipedia</a> #jf4 #bigcatvibes 🐾 =))))<br />Reference: <a target="_blank" href="https://instagram.com/gauxinhtuoicuaba">https://instagram.com/gauxinhtuoicuaba</a> 🐆</p>
</blockquote>
<h3 id="heading-what-is-leopard-indexing"><strong>What is</strong> <strong>Leopard Indexing?</strong></h3>
<p>TL:DR;</p>
<blockquote>
<p>Leopard Indexing is the Zanzibar worlds version of a supercharged Bear 🐻 🏎💨except instead of running fast, it makes access control checks ridiculously quick.</p>
</blockquote>
<p><strong>Leopard is basically a precomputed indexing system</strong>. It is used in Zanzibar and authorization checks. Leopard Index efficiently handles deeply nested and wide <strong>Access-Control-List</strong> (<strong>ACL</strong>) relationships. It is primarily used for group-based permissions where users belong to hierarchical structures such as teams, roles, and shared access groups.</p>
<p><strong>Why is it needed?</strong></p>
<ul>
<li><p><strong>Standard recursion-based ACL checks are slow</strong> when a group has <strong>deep nesting</strong> (e.g., <code>Org  Department  Team  User</code>).</p>
</li>
<li><p><strong>Querying the database for every ACL lookup</strong> leads to <strong>high latency and database overload</strong>.</p>
</li>
<li><p>Leopard <strong>precomputes</strong> relationships, <strong>flattening</strong> nested permissions into <strong>efficient set lookups</strong>, reducing <strong>authorization time to O(1) instead of O(n)</strong>.</p>
</li>
</ul>
<hr />
<h2 id="heading-how-it-works"><strong>How it Works</strong></h2>
<h3 id="heading-key-concepts-ingredients-to-cook-this-speed-boosting-system"><strong>Key <s>Concepts</s> ingredients to cook this speed-boosting-system</strong></h3>
<ol>
<li><p><strong>Precomputed ACL Graphs</strong>: Converts <strong>nested ACLs</strong> into <strong>direct mappings</strong>.</p>
</li>
<li><p><strong>Set-Based Lookups</strong>: Uses <strong>skip lists</strong> and <strong>optimized data structures</strong> for <strong>fast union &amp; intersection operations</strong>.</p>
</li>
<li><p><strong>Incremental Updates</strong>: Updates index <strong>in real-time</strong> as ACLs change.</p>
</li>
</ol>
<h3 id="heading-example-organization-hierarchy"><strong>Example: Organization Hierarchy</strong></h3>
<ul>
<li>Suppose we have <strong>this ACL structure</strong>:</li>
</ul>
<pre><code class="lang-plaintext">Company  Department  Team  User
</code></pre>
<ul>
<li>Instead of <strong>traversing relationships at runtime</strong>, Leopard <strong>precomputes flattened sets</strong>:</li>
</ul>
<pre><code class="lang-plaintext">Leopard Index:
    company:acme  { user:123, user:456, user:789 }
    department:engineering  { user:123, user:456 }
    team:frontend  { user:123 }
</code></pre>
<p> <strong>Now, checking if</strong> <code>user:123</code> belongs to <code>company:acme</code> is an O(1) lookup.</p>
<hr />
<h2 id="heading-how-it-optimizes-checks"><strong>How it Optimizes Checks</strong></h2>
<h3 id="heading-step-1-flatten-acl-relationships"><strong>Step 1: Flatten ACL Relationships</strong></h3>
<p>Instead of evaluating <strong>nested groups recursively</strong>, Leopard <strong>precomputes all relationships</strong>.</p>
<h4 id="heading-before-leopard-recursive-lookups"><strong>Before Leopard (Recursive Lookups)</strong></h4>
<pre><code class="lang-plaintext">1. Check user:123 in team:frontend 
2. Check team:frontend in department:engineering 
3. Check department:engineering in company:acme  (User is found)
</code></pre>
<ul>
<li><p><strong>Slow O(n) performance</strong></p>
</li>
<li><p><strong>Each check requires a DB lookup</strong></p>
</li>
</ul>
<h4 id="heading-with-leopard-o1-lookup"><strong>With Leopard (O(1) Lookup))</strong></h4>
<pre><code class="lang-plaintext">company:acme  { user:123, user:456, user:789 }
</code></pre>
<ul>
<li><p><strong>Single lookup in precomputed index</strong></p>
</li>
<li><p><strong>Blazing fast O(1) check</strong> </p>
</li>
</ul>
<hr />
<h2 id="heading-architecture"><strong>Architecture</strong></h2>
<h3 id="heading-diagram-of-gaus-architecture">Diagram of Gus <strong>Architecture</strong></h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742226140840/13e97460-45d2-4332-aa03-ffd83dbd397f.jpeg" alt class="image--center mx-auto" /></p>
<p>(Ops, wrong diagram, nvm =)))</p>
<h3 id="heading-leopard-index">Leopard Index:</h3>
<pre><code class="lang-mermaid">graph TD;
    A[User Requests Access] --&gt;|Check| B[Zanzibar Server];
    B --&gt;|Query| C[Leopard Index];
    C --&gt;|Lookup user in precomputed sets| D[Return ALLOW/DENY];
    C --&gt;|If Not Found| E[Fallback to Spanner DB];
    E --&gt;|Resolve ACLs| F[Update Leopard Index];
    F --&gt;|Update Precomputed Sets| C;
</code></pre>
<p> <strong>Fastest path:</strong> <strong>Leopard returns decision instantly</strong>.<br /> <strong>Fallback path:</strong> If data is missing, it queries Spanner <strong>once</strong>, then updates Leopard.</p>
<hr />
<h2 id="heading-storing-data"><strong>Storing Data</strong></h2>
<h3 id="heading-leopard-uses-an-efficient-set-representation"><strong>Leopard uses an efficient set representation:</strong></h3>
<pre><code class="lang-plaintext">(T, S, E)
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Field</strong></td><td><strong>Description</strong></td></tr>
</thead>
<tbody>
<tr>
<td><code>T</code></td><td><strong>Set Type</strong> (GROUP2GROUP, MEMBER2GROUP)</td></tr>
<tr>
<td><code>S</code></td><td><strong>Set ID</strong> (e.g., <code>team:frontend</code>)</td></tr>
<tr>
<td><code>E</code></td><td><strong>Element ID</strong> (e.g., <code>user:123</code>)</td></tr>
</tbody>
</table>
</div><h3 id="heading-example-flattened-acl-data"><strong>Example: Flattened ACL Data</strong></h3>
<pre><code class="lang-plaintext">GROUP2GROUP(team:frontend)  department:engineering
GROUP2GROUP(department:engineering)  company:acme
MEMBER2GROUP(user:123)  team:frontend
</code></pre>
<p>Now, <strong>checking</strong> <code>user:123</code> access to <code>company:acme</code> is just:</p>
<pre><code class="lang-plaintext">MEMBER2GROUP(user:123)  GROUP2GROUP(company:acme)  
</code></pre>
<p> <strong>Set intersection is extremely fast</strong> compared to recursive lookups.</p>
<hr />
<h2 id="heading-how-it-is-updated-in-nearreal-timehttpsenwikipediaorgwikireal-timecomputingnearreal-time"><strong>How it is Updated in</strong> <a target="_blank" href="https://en.wikipedia.org/wiki/Real-time_computing#Near_real-time"><strong><em>near[Real-Time]</em></strong></a></h2>
<h3 id="heading-incremental-indexing-no-painful-rebuilds"><strong>Incremental Indexing (No Painful Rebuilds!)</strong></h3>
<ul>
<li><p>🟢 Zanzibar uses a <strong>real-time event stream</strong> from its <strong>Watch API</strong>.</p>
</li>
<li><p>🟢 When ACLs <strong>change</strong>, Leopard <strong>updates only affected sets</strong> instead of <strong>rebuilding everything</strong> (thankfully!).</p>
</li>
</ul>
<pre><code class="lang-mermaid">sequenceDiagram
    participant Zanzibar as Zanzibar Server
    participant Leopard as Leopard Index
    participant DB as Spanner Database

    Zanzibar-&gt;&gt;DB: Write ACL Update (User added to group)
    DB-&gt;&gt;Zanzibar: Confirm ACL Write
    Zanzibar-&gt;&gt;Leopard: Send Incremental ACL Update
    Leopard-&gt;&gt;Leopard: Update Set Index
    Leopard-&gt;&gt;Zanzibar: Confirm Index Update
</code></pre>
<p> <strong>Only modified sets are updated, keeping operations fast.</strong></p>
<hr />
<h2 id="heading-leopard-vs-traditional-lookups"><strong>Leopard vs. Traditional Lookups</strong></h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Feature</strong></td><td><strong>Traditional lookups</strong>(🥲)</td><td><strong>Leopard Index</strong>(😎)</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Check Complexity</strong></td><td><strong>O(n) recursive queries</strong></td><td><strong>O(1) direct lookup</strong></td></tr>
<tr>
<td><strong>Performance</strong></td><td>Slow for large groups</td><td>Scales to millions of ACLs</td></tr>
<tr>
<td><strong>Data Updates</strong></td><td>Requires full recomputation</td><td><strong>Incremental updates</strong></td></tr>
<tr>
<td><strong>Storage</strong></td><td>Normalized ACLs</td><td><strong>Precomputed flattened sets</strong></td></tr>
</tbody>
</table>
</div><p>📌 <strong>Leopard makes group-based access checks 1000x faster</strong> 🚀.</p>
<hr />
<h2 id="heading-why-you-should-care-about-gauhttpsinstagramcomgauxinhtuoicuaba"><strong>Why You Should Care About</strong> <a target="_blank" href="https://instagram.com/gauxinhtuoicuaba"><strong>Gu</strong></a> <strong>🧐</strong></h2>
<p> <strong>O(1) Lookup Performance</strong>  No more waiting for slow queries.<br /> <strong>Precomputed Set Relationships</strong>  ACL checks in milliseconds.<br /> <strong>Incremental Updates</strong>  Never rebuilds everything from scratch.<br /> <strong>Cache-Friendly</strong>  Avoids repeated DB hits, making things <strong>blazing fast</strong>.</p>
<hr />
<h3 id="heading-key-takeaway"><strong>📌 Key Takeaway</strong></h3>
<p>Leopard is a <strong></strong> <em>nah, too long</em>.</p>
<blockquote>
<p>Wait, O(1)? Thats not just fastthats teleportatio<em>n 😉!</em></p>
</blockquote>
<p>c": cutesy: <em>adjective -</em> cute to a <a target="_blank" href="https://www.google.com/search?sca_esv=a84006a3a0467662&amp;sxsrf=AHTn8zpSvaqJ1Y-5OonTbhv1pYrFz4J2Uw:1742226643083&amp;q=sentimental&amp;si=APYL9btEN2SiQ9h4o5Ckf6vYFXRYHo0QI9tiJJeEv0_15K7bldjbzhZc5LvvH7gx2k-PNKSrorZ5SR406mHgtumLxrtksOPW3DweuqDhN1nc-V_yNQcPCWs%3D&amp;expnd=1&amp;sa=X&amp;ved=2ahUKEwicjreBvJGMAxU3XGwGHfL-EYkQyecJegQIRxAQ">sentimental</a> or <a target="_blank" href="https://www.google.com/search?sca_esv=a84006a3a0467662&amp;sxsrf=AHTn8zpSvaqJ1Y-5OonTbhv1pYrFz4J2Uw:1742226643083&amp;q=mawkish&amp;si=APYL9btezPaTUY7KecSEHRUsL7ycFrZX9Mncqu816dmJQGFWN7SFe_-M8KNKW-LXWS_95DJPLHVb3BuSTcbA4-riTgowUT6A6KKymYUU9DDuP02nmnJfQDQ%3D&amp;expnd=1&amp;sa=X&amp;ved=2ahUKEwicjreBvJGMAxU3XGwGHfL-EYkQyecJegQIRxAR">mawkish</a> extent. e.g. "hair pulled back in cutesy little bows"</p>
]]></description><link>https://thediligentengineer.com/leopard-the-c-of-o1-indexing-system</link><guid isPermaLink="true">https://thediligentengineer.com/leopard-the-c-of-o1-indexing-system</guid><category><![CDATA[Gau]]></category><category><![CDATA[architecture]]></category><category><![CDATA[leopard ]]></category><category><![CDATA[optimization]]></category><category><![CDATA[indexing]]></category><category><![CDATA[Databases]]></category><category><![CDATA[zanzibar ]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Do You Use Mutex in Node.js Servers?]]></title><description><![CDATA[<p><strong>TL;DR:</strong> While mutexes are commonly associated with multi-threaded programming, they are also highly useful in Node.js, a single-threaded environment. They help coordinate access to shared resources and prevent redundant or conflicting operations, especially in scenarios like database queries or cache management.</p>
<hr />
<h2 id="heading-what-is-a-mutex">What Is a Mutex?</h2>
<p>A <strong>mutex</strong> (short for <strong>mutual exclusion</strong>) is a mechanism that allows only one thread or process to access a critical section of code at a time. This ensures that shared resources are not simultaneously accessed or modified in ways that lead to conflicts or inconsistent states.</p>
<p>Under the hood, a mutex uses the following core concepts:</p>
<ol>
<li><p><strong>State Management</strong>:<br /> The mutex maintains a state, typically a boolean flag (<code>locked</code>), indicating whether it is currently held by a process.</p>
</li>
<li><p><strong>Lock Acquisition</strong>:<br /> When a task attempts to acquire the lock, it checks the <code>locked</code> state:</p>
<ul>
<li><p>If the lock is <strong>unlocked</strong>, the task acquires it and sets the state to <code>locked</code>.</p>
</li>
<li><p>If the lock is <strong>already locked</strong>, the task is queued for execution once the lock becomes available.</p>
</li>
</ul>
</li>
<li><p><strong>Queue Management</strong>:<br /> Tasks that cannot acquire the lock immediately are added to a queue. The mutex processes this queue sequentially as the lock becomes available.</p>
</li>
<li><p><strong>Lock Release</strong>:<br /> Once the task holding the lock is completed, the lock is released by:</p>
<ul>
<li><p>Setting <code>locked</code> to <code>false</code>.</p>
</li>
<li><p>Notifying the next task in the queue (if any) to acquire the lock.</p>
</li>
</ul>
</li>
</ol>
<p>This approach ensures that no two tasks can access the critical section simultaneously.</p>
<p>In Node.js, despite being single-threaded, mutexes can still play a crucial role. Why? Because Node.js applications can have asynchronous operations executing concurrently. These asynchronous tasks can lead to race conditions or redundant operations without proper coordination.</p>
<pre><code class="lang-mermaid">sequenceDiagram
    participant Task1
    participant Task2
    participant Mutex
    participant State

    Note over State: Initial State: Free
    Task1-&gt;&gt;Mutex: Request lock
    Mutex-&gt;&gt;State: Transition to Acquired
    State--&gt;&gt;Task1: Lock acquired (State: Locked)
    Task1-&gt;&gt;Mutex: Access resource
    Task2-&gt;&gt;Mutex: Request lock
    Mutex--&gt;&gt;Task2: Wait (State: Waiting)
    Task1-&gt;&gt;Mutex: Release lock
    Mutex-&gt;&gt;State: Transition to Free
    State--&gt;&gt;Task2: Next task acquires lock
    Task2-&gt;&gt;Mutex: Access resource
    Task2-&gt;&gt;Mutex: Release lock
    Mutex-&gt;&gt;State: Transition to Free
    State--&gt;&gt;[All tasks]: Lock available
</code></pre>
<h3 id="heading-common-misconception">Common Misconception</h3>
<p>Many developers often associate mutexes with multi-threaded programming, but their utility extends far beyond that. In asynchronous environments like Node.js, where multiple operations may run concurrently, mutexes play a crucial role in managing access to shared resources. This helps prevent race conditions and redundant operations, ensuring that resources are accessed in a controlled and predictable manner.</p>
<p>As the saying goes,</p>
<blockquote>
<p><strong>Concurrency is not parallelism</strong></p>
</blockquote>
<p>While Node.js operates on a single thread, it handles many asynchronous tasks concurrently. Mutexes help manage this concurrency by allowing only one task to access a critical section at a time, making it possible to safely coordinate access to shared resources, even in an environment where tasks run concurrently but not in parallel.</p>
<hr />
<h2 id="heading-real-world-scenarios">Real-World Scenarios</h2>
<p>Lets explore two examples where mutexes prove invaluable in Node.js:</p>
<h3 id="heading-1-preventing-redundant-database-queries">1. Preventing Redundant Database Queries</h3>
<p>Imagine a shared API endpoint that fetches a list of contacts. The database query takes 10 seconds to complete, and the result is cached for faster subsequent access. If 1,000 requests hit the endpoint during the query's execution, they could trigger 1,000 redundant database queries instead of waiting for the first query to complete.</p>
<h4 id="heading-solution-mutex-based-cache-population">Solution: Mutex-Based Cache Population</h4>
<p>Heres how you can use a mutex to ensure only one query runs:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { Cache } <span class="hljs-keyword">from</span> <span class="hljs-string">'cache-manager'</span>;
<span class="hljs-keyword">import</span> { InjectCacheManager } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/cache-manager'</span>;
<span class="hljs-keyword">import</span> { Mutex } <span class="hljs-keyword">from</span> <span class="hljs-string">'async-mutex'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ContactsService {
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> mutex = <span class="hljs-keyword">new</span> Mutex();

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    <span class="hljs-meta">@InjectCacheManager</span>() <span class="hljs-keyword">private</span> cacheManager: Cache,
  </span>) {}

  <span class="hljs-keyword">async</span> getContacts(): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">any</span>[]&gt; {
    <span class="hljs-keyword">const</span> CACHE_KEY = <span class="hljs-string">'contacts'</span>;

    <span class="hljs-comment">// Check cache</span>
    <span class="hljs-keyword">const</span> cachedContacts = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.cacheManager.get(CACHE_KEY);
    <span class="hljs-keyword">if</span> (cachedContacts) {
      <span class="hljs-keyword">return</span> cachedContacts <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>[];
    }

    <span class="hljs-comment">// Acquire mutex lock</span>
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.mutex.runExclusive(<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-comment">// Double-check cache in case it was populated while waiting</span>
      <span class="hljs-keyword">const</span> doubleCheckCache = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.cacheManager.get(CACHE_KEY);
      <span class="hljs-keyword">if</span> (doubleCheckCache) {
        <span class="hljs-keyword">return</span> doubleCheckCache <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>[];
      }

      <span class="hljs-comment">// Fetch data from database</span>
      <span class="hljs-keyword">const</span> contacts = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.fetchContactsFromDb();

      <span class="hljs-comment">// Store in cache</span>
      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.cacheManager.set(CACHE_KEY, contacts, { ttl: <span class="hljs-number">60</span> });

      <span class="hljs-keyword">return</span> contacts;
    });
  }

  <span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> fetchContactsFromDb(): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">any</span>[]&gt; {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Querying database...'</span>);
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, <span class="hljs-number">10000</span>)); <span class="hljs-comment">// Simulate 10s delay</span>
    <span class="hljs-keyword">return</span> [{ id: <span class="hljs-number">1</span>, name: <span class="hljs-string">'John Doe'</span> }, { id: <span class="hljs-number">2</span>, name: <span class="hljs-string">'Jane Smith'</span> }];
  }
}
</code></pre>
<h4 id="heading-diagram-mermaid">Diagram (Mermaid):</h4>
<pre><code class="lang-mermaid">sequenceDiagram
    participant Client1
    participant Client2
    participant Server
    participant Cache
    participant DB

    Client1-&gt;&gt;Server: Request contacts
    Server-&gt;&gt;Cache: Check cache
    Cache--&gt;&gt;Server: Cache miss
    Server-&gt;&gt;DB: Query contacts
    Client2-&gt;&gt;Server: Request contacts
    Server--&gt;&gt;Client2: Wait (locked)
    DB--&gt;&gt;Server: Return contacts
    Server-&gt;&gt;Cache: Update cache
    Cache--&gt;&gt;Server: Success
    Server--&gt;&gt;Client1: Return contacts
    Server--&gt;&gt;Client2: Return cached contacts
</code></pre>
<hr />
<h3 id="heading-2-coordinating-file-uploads">2. Coordinating File Uploads</h3>
<p>Imagine a file upload service where users can upload files that are processed and stored in a cloud bucket. If multiple requests try to upload files with the same name simultaneously, they might overwrite each others data or create duplicates.</p>
<h4 id="heading-solution-mutex-based-file-upload-coordination">Solution: Mutex-Based File Upload Coordination</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Mutex } <span class="hljs-keyword">from</span> <span class="hljs-string">'async-mutex'</span>;

<span class="hljs-keyword">class</span> FileUploadService {
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> mutex = <span class="hljs-keyword">new</span> Mutex();

  <span class="hljs-keyword">async</span> uploadFile(fileName: <span class="hljs-built_in">string</span>, fileContent: Buffer): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; {
    <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.mutex.runExclusive(<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.fileExists(fileName)) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'File already exists'</span>);
      }

      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.saveFile(fileName, fileContent);
    });
  }

  <span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> fileExists(fileName: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">boolean</span>&gt; {
    <span class="hljs-comment">// Check if file exists in storage</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Checking existence for <span class="hljs-subst">${fileName}</span>`</span>);
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, <span class="hljs-number">100</span>));
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; <span class="hljs-comment">// Simulate no file exists</span>
  }

  <span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> saveFile(fileName: <span class="hljs-built_in">string</span>, fileContent: Buffer): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Saving file: <span class="hljs-subst">${fileName}</span>`</span>);
    <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, <span class="hljs-number">500</span>));
  }
}
</code></pre>
<h4 id="heading-diagram-mermaid-1">Diagram (Mermaid):</h4>
<pre><code class="lang-mermaid">sequenceDiagram
    participant Request1
    participant Request2
    participant Service
    participant Storage

    Request1-&gt;&gt;Service: Upload file1
    Service-&gt;&gt;Storage: Check existence
    Storage--&gt;&gt;Service: File not exists
    Service-&gt;&gt;Storage: Save file1
    Request2-&gt;&gt;Service: Upload file1
    Service--&gt;&gt;Request2: Wait (locked)
    Storage--&gt;&gt;Service: File saved
    Service--&gt;&gt;Request1: Success
    Service-&gt;&gt;Storage: Check existence
    Storage--&gt;&gt;Service: File exists
    Service--&gt;&gt;Request2: Error: File already exists
</code></pre>
<hr />
<h2 id="heading-why-use-mutex-in-nodejs">Why Use Mutex in Node.js?</h2>
<ol>
<li><p><strong>Prevent Redundancy:</strong> Avoid executing the same expensive operation multiple times.</p>
</li>
<li><p><strong>Ensure Consistency:</strong> Protect shared resources from conflicting updates.</p>
</li>
<li><p><strong>Simplify Asynchronous Coordination:</strong> Manage race conditions cleanly and predictably.</p>
</li>
</ol>
<hr />
<h2 id="heading-alternative-solutions"><strong>Alternative solutions</strong></h2>
<p>While mutexes are effective for managing concurrency in Node.js, they are not the only solution. Depending on your use case, there are several <strong>alternative solutions</strong> for handling concurrency and shared resource management in Node.js. Here are some alternatives:</p>
<h3 id="heading-1-locks-with-redis-distributed-locking">1. <strong>Locks with Redis (Distributed Locking)</strong></h3>
<p>If you're working in a distributed environment or need to scale across multiple processes or machines, Redis can be used to create distributed locks. Redis provides a lightweight and highly performant solution to implement locks via the <strong>SETNX</strong> command (set if not exists) or libraries like <strong>Redlock</strong>.</p>
<h4 id="heading-use-case">Use Case:</h4>
<ul>
<li>Distributed systems with multiple instances of Node.js servers needing synchronized access to resources.</li>
</ul>
<h4 id="heading-code-example">Code Example:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'redis'</span>;
<span class="hljs-keyword">import</span> Redlock <span class="hljs-keyword">from</span> <span class="hljs-string">'redlock'</span>;

<span class="hljs-keyword">const</span> client = createClient();
<span class="hljs-keyword">const</span> redlock = <span class="hljs-keyword">new</span> Redlock([client]);

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchContactsWithRedisLock</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> resource = <span class="hljs-string">'contacts-lock'</span>;
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> lock = <span class="hljs-keyword">await</span> redlock.lock(resource, <span class="hljs-number">10000</span>); <span class="hljs-comment">// 10 seconds</span>
    <span class="hljs-keyword">const</span> contacts = <span class="hljs-keyword">await</span> fetchContactsFromDb();
    <span class="hljs-comment">// Do something with the contacts...</span>
    lock.unlock();
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Could not acquire lock'</span>, error);
  }
}
</code></pre>
<h3 id="heading-2-semaphore-rate-limiting">2. <strong>Semaphore (Rate Limiting)</strong></h3>
<p>A <strong>semaphore</strong> is another synchronization primitive that controls access to a particular resource by multiple processes in a concurrent system. A semaphore keeps track of how many "tokens" are available for tasks to acquire. Semaphore-based solutions are especially useful for rate-limiting access to a resource.</p>
<h4 id="heading-use-case-1">Use Case:</h4>
<ul>
<li>Rate-limiting for APIs or services to ensure only a certain number of concurrent users can access a resource.</li>
</ul>
<h4 id="heading-code-example-1">Code Example:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Semaphore } <span class="hljs-keyword">from</span> <span class="hljs-string">'semaphore-async-await'</span>;

<span class="hljs-keyword">const</span> semaphore = <span class="hljs-keyword">new</span> Semaphore(<span class="hljs-number">1</span>); <span class="hljs-comment">// Allow only one concurrent access</span>

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchContactsWithSemaphore</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> resource = <span class="hljs-keyword">await</span> semaphore.acquire();
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> contacts = <span class="hljs-keyword">await</span> fetchContactsFromDb();
    <span class="hljs-keyword">return</span> contacts;
  } <span class="hljs-keyword">finally</span> {
    semaphore.release(resource);
  }
}
</code></pre>
<h3 id="heading-3-event-emitters-for-task-coordination">3. <strong>Event Emitters for Task Coordination</strong></h3>
<p>For simpler concurrency management within a single process, you can use <strong>Node.js EventEmitters</strong> to notify other tasks when an operation is complete. While not a strict locking mechanism, EventEmitters allow you to manage the flow of asynchronous tasks and coordinate operations.</p>
<h4 id="heading-use-case-2">Use Case:</h4>
<ul>
<li>When multiple tasks depend on the completion of a single task and need to avoid redundant execution.</li>
</ul>
<h4 id="heading-code-example-2">Code Example:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { EventEmitter } <span class="hljs-keyword">from</span> <span class="hljs-string">'events'</span>;

<span class="hljs-keyword">const</span> eventEmitter = <span class="hljs-keyword">new</span> EventEmitter();

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchContactsAndNotify</span>(<span class="hljs-params"></span>) </span>{
  fetchContactsFromDb()
    .then(<span class="hljs-function"><span class="hljs-params">contacts</span> =&gt;</span> {
      eventEmitter.emit(<span class="hljs-string">'contacts-fetched'</span>, contacts);
    });
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleFetchedContacts</span>(<span class="hljs-params"></span>) </span>{
  eventEmitter.once(<span class="hljs-string">'contacts-fetched'</span>, <span class="hljs-function">(<span class="hljs-params">contacts</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Received contacts:'</span>, contacts);
  });
}

handleFetchedContacts();
fetchContactsAndNotify();
</code></pre>
<h3 id="heading-4-worker-queues-eg-bull-or-kue">4. <strong>Worker Queues (e.g., Bull or Kue)</strong></h3>
<p>Using <strong>worker queues</strong> like <strong>Bull</strong> or <strong>Kue</strong> can help with managing task concurrency in Node.js. These libraries allow you to create jobs that can be processed by worker processes, controlling concurrency and ensuring that resources are accessed in an orderly manner.</p>
<h4 id="heading-use-case-3">Use Case:</h4>
<ul>
<li>Managing task queues where only a certain number of workers can access a resource at any given time.</li>
</ul>
<h4 id="heading-code-example-with-bull">Code Example with Bull:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Queue, Worker } <span class="hljs-keyword">from</span> <span class="hljs-string">'bullmq'</span>;

<span class="hljs-keyword">const</span> queue = <span class="hljs-keyword">new</span> Queue(<span class="hljs-string">'fetch-contacts'</span>);
<span class="hljs-keyword">const</span> worker = <span class="hljs-keyword">new</span> Worker(<span class="hljs-string">'fetch-contacts'</span>, <span class="hljs-keyword">async</span> job =&gt; {
  <span class="hljs-keyword">const</span> contacts = <span class="hljs-keyword">await</span> fetchContactsFromDb();
  <span class="hljs-comment">// Process contacts...</span>
}, {
  limiter: {
    groupKey: <span class="hljs-string">'fetch-contacts'</span>,
    max: <span class="hljs-number">1</span>, <span class="hljs-comment">// Only allow 1 worker at a time</span>
    duration: <span class="hljs-number">1000</span> <span class="hljs-comment">// Limit requests per second</span>
  }
});
</code></pre>
<h3 id="heading-5-promise-based-locks">5. <strong>Promise-based Locks</strong></h3>
<p>In a simpler case, you can create a <strong>promise-based lock</strong> where the <code>lock</code> is a promise that other tasks can wait on before proceeding. This approach is helpful for managing a shared resource in single-threaded environments like Node.js.</p>
<h4 id="heading-use-case-4">Use Case:</h4>
<ul>
<li>Managing access to a critical section of code with minimal complexity.</li>
</ul>
<h4 id="heading-code-example-3">Code Example:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> PromiseLock {
  <span class="hljs-keyword">private</span> lock: <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; = <span class="hljs-built_in">Promise</span>.resolve();

  acquire() {
    <span class="hljs-keyword">let</span> release: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>;
    <span class="hljs-keyword">const</span> newLock = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt;(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> release = resolve);
    <span class="hljs-keyword">const</span> currentLock = <span class="hljs-built_in">this</span>.lock;
    <span class="hljs-built_in">this</span>.lock = <span class="hljs-built_in">this</span>.lock.then(<span class="hljs-function">() =&gt;</span> newLock);
    <span class="hljs-keyword">return</span> currentLock.then(<span class="hljs-function">() =&gt;</span> release);
  }
}

<span class="hljs-keyword">const</span> lock = <span class="hljs-keyword">new</span> PromiseLock();

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchContacts</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> release = <span class="hljs-keyword">await</span> lock.acquire();
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> contacts = <span class="hljs-keyword">await</span> fetchContactsFromDb();
    <span class="hljs-keyword">return</span> contacts;
  } <span class="hljs-keyword">finally</span> {
    release();
  }
}
</code></pre>
<h3 id="heading-6-single-responsibility-pattern-with-a-task-queue">6. <strong>Single Responsibility Pattern with a Task Queue</strong></h3>
<p>Sometimes, a simpler design pattern can solve concurrency challenges. You could use a <strong>task queue</strong> that ensures only one task accesses a shared resource at any given time by using a <strong>single-responsibility</strong> approach for managing a shared state.</p>
<h4 id="heading-use-case-5">Use Case:</h4>
<ul>
<li>Preventing race conditions by ensuring one task processes data at a time.</li>
</ul>
<h4 id="heading-code-example-4">Code Example:</h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> TaskQueue {
  <span class="hljs-keyword">private</span> queue: (<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>)[] = [];
  <span class="hljs-keyword">private</span> isProcessing = <span class="hljs-literal">false</span>;

  enqueue(task: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>) {
    <span class="hljs-built_in">this</span>.queue.push(task);
    <span class="hljs-built_in">this</span>.processQueue();
  }

  <span class="hljs-keyword">async</span> processQueue() {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isProcessing || <span class="hljs-built_in">this</span>.queue.length === <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span>;
    <span class="hljs-built_in">this</span>.isProcessing = <span class="hljs-literal">true</span>;
    <span class="hljs-keyword">const</span> task = <span class="hljs-built_in">this</span>.queue.shift();
    <span class="hljs-keyword">await</span> task();
    <span class="hljs-built_in">this</span>.isProcessing = <span class="hljs-literal">false</span>;
    <span class="hljs-built_in">this</span>.processQueue();
  }
}

<span class="hljs-keyword">const</span> taskQueue = <span class="hljs-keyword">new</span> TaskQueue();

taskQueue.enqueue(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> contacts = <span class="hljs-keyword">await</span> fetchContactsFromDb();
  <span class="hljs-built_in">console</span>.log(contacts);
});
</code></pre>
<hr />
<h3 id="heading-comparison-of-alternatives">Comparison of Alternatives</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Approach</strong></td><td><strong>Best For</strong></td><td><strong>Concurrency Level</strong></td><td><strong>Complexity</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Mutex (async-mutex)</strong></td><td>Single-node concurrency control</td><td>High (single thread)</td><td>Moderate</td></tr>
<tr>
<td><strong>Redis Lock</strong></td><td>Distributed systems or microservices</td><td>High (across machines)</td><td>High</td></tr>
<tr>
<td><strong>Semaphore</strong></td><td>Rate limiting, controlling the number of concurrent tasks</td><td>Medium</td><td>Low</td></tr>
<tr>
<td><strong>Event Emitters</strong></td><td>Task coordination in single-process systems</td><td>Medium</td><td>Low</td></tr>
<tr>
<td><strong>Worker Queues (Bull)</strong></td><td>Task queues with concurrency control</td><td>High</td><td>High</td></tr>
<tr>
<td><strong>Promise-based Locks</strong></td><td>Simple concurrency management in single-threaded systems</td><td>Low (single thread)</td><td>Low</td></tr>
<tr>
<td><strong>Task Queue (SRP)</strong></td><td>Sequential task processing with minimal concurrency</td><td>Low</td><td>Low</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>While <strong>mutexes</strong> are an effective solution for managing shared resources in Node.js, you should consider these alternatives based on your specific needs:</p>
<ul>
<li><p><strong>Redis locks</strong> or <strong>distributed locks</strong> are great for large-scale, distributed systems.</p>
</li>
<li><p><strong>Semaphores</strong> are useful for rate-limiting and managing controlled concurrency.</p>
</li>
<li><p><strong>Promise-based locks</strong> or <strong>task queues</strong> offer lightweight solutions for simpler scenarios.</p>
</li>
</ul>
<p>Mutexes arent just for multi-threaded programming. In a single-threaded, asynchronous environment like Node.js, they provide a powerful tool for managing shared resources, ensuring consistent behavior, and optimizing performance. By adopting mutexes in scenarios like cache management and file uploads, you can make your applications more robust and efficient.</p>
<p>Give mutexes a try in your Node.js projects and see how they simplify concurrency challenges.</p>
]]></description><link>https://thediligentengineer.com/do-you-use-mutex-in-nodejs-servers</link><guid isPermaLink="true">https://thediligentengineer.com/do-you-use-mutex-in-nodejs-servers</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[concurrency]]></category><category><![CDATA[mutex]]></category><category><![CDATA[semaphore]]></category><category><![CDATA[lock]]></category><category><![CDATA[distributed system]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Frequent Feedback vs. Corrective Feedback in Engineering]]></title><description><![CDATA[<p>In the fast-paced world of IT, feedback is not just a toolit's the cornerstone of growth, innovation, and collaboration. Whether you're mentoring a new hire or guiding a seasoned developer, the way you deliver feedback can shape careers, improve team dynamics, and elevate project outcomes. Among the various feedback strategies, <strong>frequent feedback</strong> and <strong>corrective feedback</strong> play pivotal roles. Lets explore these types, how to implement them effectively, and their profound impact on team development.</p>
<hr />
<h2 id="heading-what-is-frequent-feedback"><strong>What Is Frequent Feedback?</strong></h2>
<p>Frequent feedback is a continuous process of providing constructive input and encouragement to team members. Unlike annual performance reviews or milestone-based evaluations, this type of feedback happens regularlydaily, weekly, or at key moments of collaboration.</p>
<h3 id="heading-key-actions-for-frequent-feedback"><strong>Key Actions for Frequent Feedback</strong></h3>
<ol>
<li><p><strong>Be Immediate and Specific</strong><br /> Recognize achievements or address issues as they arise. For example, after a sprint demo, say: <em>Great job on implementing that caching strategyit improved response time by 40%!</em></p>
</li>
<li><p><strong>Focus on Positives as Well as Improvements</strong><br /> Celebrate small wins. It reinforces good behaviors and motivates individuals to aim higher.</p>
</li>
<li><p><strong>Tie Feedback to Team or Individual Goals</strong><br /> Frame your input around the persons career objectives or the projects success.</p>
</li>
</ol>
<hr />
<h2 id="heading-corrective-feedback-addressing-areas-of-improvement"><strong>Corrective Feedback: Addressing Areas of Improvement</strong></h2>
<p>Corrective feedback is the process of addressing a behavior, decision, or skill gap that requires improvement. It's often more delicate because it focuses on what went wrong or what could be better.</p>
<h3 id="heading-key-actions-for-corrective-feedback"><strong>Key Actions for Corrective Feedback</strong></h3>
<ol>
<li><p><strong>Be Empathetic and Solution-Oriented</strong><br /> Example: Instead of saying, <em>Your code is too messy,</em> say, <em>Lets work on improving the readability of this section so the team can maintain it easily.</em></p>
</li>
<li><p><strong>Frame It Around Growth</strong><br /> Emphasize the potential for improvement rather than the problem itself.</p>
</li>
<li><p><strong>Provide Actionable Next Steps</strong><br /> Suggest specific ways to address the issue, such as code reviews, pairing sessions, or training.</p>
</li>
<li><p><strong>Balance with Encouragement</strong><br /> Acknowledge what the person does well while addressing the challenge. This builds trust and receptiveness.</p>
</li>
</ol>
<hr />
<h2 id="heading-frequent-vs-corrective-feedback-when-and-how-to-use-them"><strong>Frequent vs. Corrective Feedback: When and How to Use Them</strong></h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Aspect</strong></td><td><strong>Frequent Feedback</strong></td><td><strong>Corrective Feedback</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Purpose</strong></td><td>Reinforce positive behaviors and maintain momentum.</td><td>Address specific issues for growth and improvement.</td></tr>
<tr>
<td><strong>Frequency</strong></td><td>Ongoing, integrated into daily/weekly routines.</td><td>Occasional, as issues arise or during formal reviews.</td></tr>
<tr>
<td><strong>Tone</strong></td><td>Encouraging, positive, collaborative.</td><td>Constructive, empathetic, solution-driven.</td></tr>
<tr>
<td><strong>Effect on Morale</strong></td><td>Boosts confidence and engagement.</td><td>May challenge but fosters accountability.</td></tr>
<tr>
<td><strong>Example</strong></td><td>Your documentation on this feature is clear and helpful!</td><td>Your solution works, but lets consider how to reduce its complexity.</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-why-balance-both-feedback-types-in-engineering-teams"><strong>Why Balance Both Feedback Types in Engineering Teams?</strong></h2>
<ol>
<li><p><strong>Fostering a Growth Culture</strong><br /> Combining frequent praise with constructive guidance creates an environment where team members feel valued and challenged.</p>
</li>
<li><p><strong>Accelerating Skill Development</strong><br /> While frequent feedback keeps confidence high, corrective feedback ensures skills and habits evolve.</p>
</li>
<li><p><strong>Improved Team Cohesion</strong><br /> Regular, transparent communication helps build trust and mitigates misunderstandings.</p>
</li>
<li><p><strong>Resilience and Adaptability</strong><br /> Corrective feedback, delivered effectively, makes team members more receptive to change and criticism, key traits in IT.</p>
</li>
</ol>
<hr />
<h2 id="heading-tips-for-delivering-feedback-effectively"><strong>Tips for Delivering Feedback Effectively</strong></h2>
<ol>
<li><p><strong>Be Consistent</strong><br /> Feedback should be a habit, not an event. Schedule regular check-ins to discuss progress.</p>
</li>
<li><p><strong>Leverage Data and Examples</strong><br /> Concrete examples make feedback actionable and objective. For instance, refer to specific code commits, incidents, or metrics.</p>
</li>
<li><p><strong>Listen Actively</strong><br /> Feedback is a two-way street. Allow team members to share their perspective.</p>
</li>
<li><p><strong>Document and Follow Up</strong><br /> Track feedback in one-on-ones or performance reviews to measure growth and reinforce accountability.</p>
</li>
<li><p><strong>Tailor Your Approach</strong><br /> Each individual is different. Some may prefer direct feedback, while others need a softer touch.</p>
</li>
</ol>
<hr />
<h2 id="heading-the-ripple-effect-impact-of-effective-feedback"><strong>The Ripple Effect: Impact of Effective Feedback</strong></h2>
<p>When used effectively, frequent and corrective feedback doesnt just enhance individual performanceit transforms teams:</p>
<ul>
<li><p><strong>Higher Productivity</strong>: Clearer expectations and faster course corrections minimize wasted effort.</p>
</li>
<li><p><strong>Stronger Relationships</strong>: A culture of transparency fosters trust and collaboration.</p>
</li>
<li><p><strong>Greater Innovation</strong>: Constructive feedback encourages calculated risks and creative problem-solving.</p>
</li>
</ul>
<hr />
<h2 id="heading-feedback-is-leadership-in-action"><strong>Feedback Is Leadership in Action</strong></h2>
<p>As mentors and leaders, our ability to deliver feedback defines our effectiveness. By mastering frequent and corrective feedback, we empower our engineering teams to grow stronger, innovate faster, and tackle challenges more confidently.</p>
<p>The next time you engage with your team, ask yourself: <em>Am I balancing encouragement with challenge? Am I building trust and accountability in equal measure?</em> The answers to these questions will pave the way for long-term success.</p>
<h2 id="heading-references"><strong>References</strong></h2>
<p>Valuable references on corrective and frequent feedback in the workplace:</p>
<ol>
<li><p><strong>Business Management Daily</strong> - This article discusses how to build a feedback culture, emphasizing that effective feedback should be continuous and part of everyday work life. It highlights the importance of constructive feedback and its role in fostering a culture of trust and improvement. <a target="_blank" href="http://www.businessmanagementdaily.com/74763/workplace-feedback-the-backbone-of-effective-communication/">Read more.</a></p>
</li>
<li><p><strong>BetterUp</strong> - Provides an overview of different types of feedback, including constructive, upward, and real-time feedback. It explains how constructive feedback can improve employee importance of creating a psychologically safe environment for open communication. <a target="_blank" href="https://www.betterup.com/blog/types-of-feedback">Read more here</a>.</p>
</li>
<li><p><strong>Greater Good Science Center (UC Berkeley)</strong> - Explores how feedback loops strengthen team relationships and offer actionable tip back delivery, such as avoiding the "feedback sandwich" and using radical candor to create meaningful and honest communication. <a target="_blank" href="https://greatergood.berkeley.edu/article/item/nine_tips_for_giving_better_feedback_at_work">Read more here</a>.</p>
</li>
<li><p><a target="_blank" href="https://intime.uni.edu/frequent-feedback">Frequent feedback</a>: University of Northern Iowa</p>
</li>
<li><p><a target="_blank" href="https://ctb.ku.edu/en/table-of-contents/advocacy/encouragement-education/corrective-feedback/main#:~:text=Corrective%20feedback%20is%20information%20provided,effective%20advocacy%20or%20public%20policy.">Corrective feedback</a>: The University of Kansas</p>
</li>
</ol>
]]></description><link>https://thediligentengineer.com/frequent-feedback-vs-corrective-feedback-in-engineering</link><guid isPermaLink="true">https://thediligentengineer.com/frequent-feedback-vs-corrective-feedback-in-engineering</guid><category><![CDATA[mentorship]]></category><category><![CDATA[leadership]]></category><category><![CDATA[management]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Most Asked Questions During My Job Searching Journey]]></title><description><![CDATA[<p>As I progressed through my job search, I encountered some insightful and frequently asked questions that challenged me to reflect on my professional journey. Im sharing my answers to these questions, which might provide value to others preparing for similar situations.</p>
<hr />
<h3 id="heading-what-was-the-proudest-feature-you-have-developed"><strong>What was the proudest feature you have developed?</strong></h3>
<p>One of my proudest achievements was deploying my very first product to production: <strong>the Singapore Loyalty Program application, <em>sG</em></strong>. This project was particularly meaningful as it marked a true <em>0-to-1</em> journey under challenging circumstances, including being part of a small, under-resourced team.</p>
<p>I took full ownership of the product lifecycle, including:</p>
<ul>
<li><p><strong>Infrastructure setup</strong>: Configured the backend server and admin dashboard using Django.</p>
</li>
<li><p><strong>UI implementation</strong>: Built the apps interface with React Native, delivering a seamless user experience.</p>
</li>
<li><p><strong>Continuous deployment</strong>: Managed CI/CD pipelines using Jenkins and GitLab CI to ensure regular, stable updates.</p>
</li>
<li><p><strong>Client collaboration</strong>: Worked closely with stakeholders to gather feedback and improve the application iteratively.</p>
</li>
</ul>
<p>The experience was intensepushing me to the brink of burnout. However, seeing the platform go live and witnessing its impact on businesses and customers was immensely rewarding. This project strengthened my confidence in taking ownership of complex challenges, from architecture to deployment and delivering meaningful outcomes.</p>
<hr />
<h3 id="heading-what-was-the-most-challenging-technical-difficulty-you-have-solved"><strong>What was the most challenging technical difficulty you have solved?</strong></h3>
<p>One of the most technically challenging problems I faced was building an <strong>ETL pipeline for a data service</strong> while working at GT. The project constraints were formidable:</p>
<ul>
<li><p>Limited resources, including a single PostgreSQL database, one ELK node, and a single EC2 instance.</p>
</li>
<li><p>Over 20 million records for 1,000 users, requiring real-time updates.</p>
</li>
</ul>
<p>To overcome these challenges, I:</p>
<ol>
<li><p><strong>Designed an optimized database schema</strong> and implemented efficient GraphQL APIs to support fast querying.</p>
</li>
<li><p>Migrated heavy queries from SQL to <strong>Elasticsearch</strong>, enabling full-text search and large-scale data handling.</p>
</li>
<li><p>Built a robust synchronization pipeline:</p>
<ul>
<li>PostgreSQL  Our PostgreSQL  Elasticsearch, ensuring real-time data updates.</li>
</ul>
</li>
<li><p>Set up comprehensive <strong>observability</strong> with Prometheus, Grafana, and ELK to monitor and maintain system reliability.</p>
</li>
</ol>
<p>Beyond the ETL pipeline, I also managed:</p>
<ul>
<li><p>A recommender system.</p>
</li>
<li><p>A Salesforce Data Cloud ingestion service.</p>
</li>
<li><p>A payment service integrated with Stripe.</p>
</li>
</ul>
<p>This project taught me the art of designing efficient architectures and building scalable, reliable systems, even with constrained resources.</p>
<hr />
<h3 id="heading-what-was-the-biggest-mistake-you-made-as-a-developer"><strong>What was the biggest mistake you made as a developer?</strong></h3>
<p>Reflecting on my journey, one of my biggest mistakes occurred during the early stages of the sG project. As the sole developer initially, I focused on building a simple, easy-to-understand codebase to enable quick onboarding for new team members. However, I overlooked the importance of establishing <strong>linting rules and coding conventions</strong> from the outset.</p>
<p>When the team expanded, this oversight caused significant friction:</p>
<ul>
<li><p>Code conflicts became frequent due to differing IDE settings and formatting styles.</p>
</li>
<li><p>This slowed down development and impacted team efficiency.</p>
</li>
</ul>
<p>To address this, I implemented:</p>
<ul>
<li><p>Standardized <strong>linting rules</strong>.</p>
</li>
<li><p>A comprehensive <strong>coding style guide</strong>.</p>
</li>
<li><p><strong>Pre-commit hooks</strong> to enforce consistency automatically.</p>
</li>
</ul>
<p>Since then, Ive prioritized setting up foundational tools and processes early in every project to ensure smoother collaboration and maintainability as teams scale.</p>
<h3 id="heading-general-tips-for-answering-these-questions"><strong>General Tips for Answering These Questions</strong></h3>
<ol>
<li><p><strong>Use the STAR method</strong>: This structured approach helps you organize your thoughts and deliver concise, impactful answers.</p>
</li>
<li><p><strong>Be specific</strong>: Avoid vague statementsprovide details about tools, technologies, and strategies you used.</p>
</li>
<li><p><strong>Quantify outcomes</strong>: Back up your answers with measurable results (e.g., "improved system performance by 30%").</p>
</li>
<li><p><strong>Highlight transferable skills</strong>: Even if the experience is from a different domain, emphasize skills like problem-solving, teamwork, or ownership.</p>
</li>
</ol>
<hr />
<p>Reflecting on these experiences has been a valuable exercise for me during this job search. Each of these challenges helped me grow as an engineer, and I hope sharing them here provides insights or inspiration to others navigating similar paths.</p>
<p>If you have thoughts or similar experiences, Id love to hear them!</p>
<p><strong>Cheers,</strong><br /><strong>Kai</strong></p>
]]></description><link>https://thediligentengineer.com/most-asked-questions-during-my-job-searching-journey</link><guid isPermaLink="true">https://thediligentengineer.com/most-asked-questions-during-my-job-searching-journey</guid><category><![CDATA[interview]]></category><category><![CDATA[interview questions]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Building a Lightweight HTTP Client in Bash: `exec 3<>/dev/tcp/"$host"/80`]]></title><description><![CDATA[<p>In the world of web development and system administration, HTTP clients are essential tools for interacting with web services. While many developers rely on popular utilities like <code>curl</code> or <code>wget</code>, it's both educational and sometimes necessary to create a basic HTTP client using nothing but Bash. This approach not only deepens our understanding of the HTTP protocol but also proves useful in environments where standard tools may not be available.
Our Bash-based HTTP client supports the fundamental HTTP methods: <code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>DELETE</code>, and <code>OPTIONS</code>. Here's a breakdown of its key components:</p>
<ol>
<li>TCP Connection Handling
The script uses Bash's built-in <code>/dev/tcp/</code> pseudo-device to establish TCP connections. This feature, often overlooked, allows for raw socket programming directly in Bash.<pre><code class="lang-bash"><span class="hljs-built_in">exec</span> 3&lt;&gt;/dev/tcp/<span class="hljs-string">"<span class="hljs-variable">$host</span>"</span>/80
</code></pre>
This line opens a bidirectional connection to the specified host on port <code>80</code>, using file descriptor 3.</li>
<li>Request Formatting
The script constructs HTTP requests using here-documents, ensuring proper formatting of headers and body content.<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> -e <span class="hljs-string">"<span class="hljs-variable">$method</span> <span class="hljs-variable">$path</span> HTTP/1.1\r
Host: <span class="hljs-variable">$host</span>\r
Connection: close\r
Content-Length: <span class="hljs-variable">${#data}</span>\r
\r
<span class="hljs-variable">$data</span>"</span> &gt;&amp;3
</code></pre>
</li>
<li>Response Handling
After sending the request, the script reads the response using the cat command:<pre><code class="lang-bash">cat &lt;&amp;3
</code></pre>
This simple approach captures both headers and body content.</li>
<li>Method-Specific Functions
The script provides separate functions for each HTTP method, simplifying usage and improving readability.
The complete Script is on <a target="_blank" href="https://github.com/lyluongthien/rb-http-request/blob/main/rb-req-client.sh">my GitHub</a></li>
</ol>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-function"><span class="hljs-title">perform_request</span></span>() {
    <span class="hljs-built_in">local</span> method=<span class="hljs-string">"<span class="hljs-variable">$1</span>"</span>
    <span class="hljs-built_in">local</span> url=<span class="hljs-string">"<span class="hljs-variable">$2</span>"</span>
    <span class="hljs-built_in">local</span> data=<span class="hljs-string">"<span class="hljs-variable">$3</span>"</span>
    <span class="hljs-built_in">local</span> host=$(<span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$url</span>"</span> | awk -F/ <span class="hljs-string">'{print $3}'</span>)
    <span class="hljs-built_in">local</span> path=$(<span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$url</span>"</span> | awk -F/ <span class="hljs-string">'{print "/" $4}'</span>)

    <span class="hljs-built_in">exec</span> 3&lt;&gt;/dev/tcp/<span class="hljs-string">"<span class="hljs-variable">$host</span>"</span>/80

    <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"<span class="hljs-variable">$method</span> <span class="hljs-variable">$path</span> HTTP/1.1\r
Host: <span class="hljs-variable">$host</span>\r
Connection: close\r
Content-Length: <span class="hljs-variable">${#data}</span>\r
\r
<span class="hljs-variable">$data</span>"</span> &gt;&amp;3

    cat &lt;&amp;3
    <span class="hljs-built_in">exec</span> 3&gt;&amp;-
}

<span class="hljs-function"><span class="hljs-title">get_request</span></span>() {
    perform_request <span class="hljs-string">"GET"</span> <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span> <span class="hljs-string">""</span>
}

<span class="hljs-function"><span class="hljs-title">post_request</span></span>() {
    perform_request <span class="hljs-string">"POST"</span> <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span> <span class="hljs-string">"<span class="hljs-variable">$2</span>"</span>
}

<span class="hljs-function"><span class="hljs-title">put_request</span></span>() {
    perform_request <span class="hljs-string">"PUT"</span> <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span> <span class="hljs-string">"<span class="hljs-variable">$2</span>"</span>
}

<span class="hljs-function"><span class="hljs-title">delete_request</span></span>() {
    perform_request <span class="hljs-string">"DELETE"</span> <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span> <span class="hljs-string">""</span>
}

<span class="hljs-function"><span class="hljs-title">options_request</span></span>() {
    perform_request <span class="hljs-string">"OPTIONS"</span> <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span> <span class="hljs-string">""</span>
}

<span class="hljs-comment"># Usage examples</span>
<span class="hljs-comment"># get_request "http://example.com"</span>
<span class="hljs-comment"># post_request "http://example.com/api" "key1=value1&amp;key2=value2"</span>
<span class="hljs-comment"># put_request "http://example.com/api/resource" "updated_data"</span>
<span class="hljs-comment"># delete_request "http://example.com/api/resource"</span>
<span class="hljs-comment"># options_request "http://example.com"</span>
</code></pre>
<p>While this implementation is basic, it demonstrates the power and flexibility of Bash for networking tasks. It's particularly useful for quick tests, debugging, or in environments where installing additional tools is not feasible.
In our next article, we'll explore the server-side of HTTP by building a simple CRUD server in Bash, rounding out our exploration of raw HTTP handling with Bash.</p>
]]></description><link>https://thediligentengineer.com/building-a-lightweight-http-client-in-bash-exec-3devtcphost80</link><guid isPermaLink="true">https://thediligentengineer.com/building-a-lightweight-http-client-in-bash-exec-3devtcphost80</guid><category><![CDATA[Bash]]></category><category><![CDATA[backend]]></category><category><![CDATA[http]]></category><category><![CDATA[TCP]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[The React Hell]]></title><description><![CDATA[<p>After switching to the backend and system architecture, Ive always appreciated the elegance and efficiency of clean code. However, upon revisiting the front-end side of my recent projects, I was confronted with a common issue known as "React hell." This scenario arises when multiple react components or context providers nest within each other, leading to deeply nested structures that are hard to read and maintain. This post details my journey of tackling this problem with a custom solution I named <code>FlatedReact</code>.</p>
<h3 id="heading-the-problem-react-hell">The Problem: React Hell</h3>
<p>Reacts context API is incredibly powerful for managing global state and passing props through the component tree without prop drilling. However, as applications grow, its easy to end up with a situation where multiple providers are nested inside each other, creating a callback hell of sorts in React. Here's a typical example:</p>
<pre><code class="lang-jsx">&lt;AuthProvider&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThemeProvider</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">IntercomProvider</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">EmailVerificationProvider</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">TooltipProvider</span>&gt;</span>
          {children}
        <span class="hljs-tag">&lt;/<span class="hljs-name">TooltipProvider</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">EmailVerificationProvider</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">IntercomProvider</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ThemeProvider</span>&gt;</span></span>
&lt;/AuthProvider&gt;
</code></pre>
<p>While this setup works, it quickly becomes cumbersome and difficult to manage, especially as more providers are added.</p>
<h3 id="heading-the-solution-flatedreact">The Solution: FlatedReact</h3>
<p>To address this issue, I created a utility named FlatedReact. This utility flattens the provider structure, making the code cleaner and easier to read. The core idea is to use a tuple where the first element is the React function component and the second is its props. Heres the TypeScript type for it:</p>
<pre><code class="lang-jsx">type FlatedItem&lt;T <span class="hljs-keyword">extends</span> FC&lt;any&gt; = FC&lt;any&gt;&gt; = [T] | [T, (Parameters&lt;T&gt;[<span class="hljs-number">0</span>] &amp; { <span class="hljs-attr">children</span>: <span class="hljs-literal">undefined</span> }) | <span class="hljs-literal">undefined</span>];
</code></pre>
<p>I then created a helper function to facilitate creating these tuples:</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeFlatedItem</span>&lt;<span class="hljs-title">T</span> <span class="hljs-title">extends</span> (<span class="hljs-params">...args: any[]</span>) =&gt; <span class="hljs-title">any</span>&gt;(<span class="hljs-params">
  component: T, 
  props: Omit&lt;Parameters&lt;T&gt;[<span class="hljs-number">0</span>], <span class="hljs-string">'children'</span>&gt; | undefined = undefined
</span>) </span>{
  <span class="hljs-keyword">return</span> [component, props] <span class="hljs-keyword">as</span> FlatedItem&lt;T&gt;;
}
</code></pre>
<h3 id="heading-the-renderer-component">The Renderer Component</h3>
<p>The <code>Renderer</code> component is designed to take an array of these tuples and recursively render them. This effectively flattens the nested providers into a more readable structure:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Renderer = <span class="hljs-function">(<span class="hljs-params">{ components, children }: { components: FlatedItem[]; children?: ReactNode }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> renderProvider = (components: FlatedItem[], <span class="hljs-attr">children</span>: ReactNode): <span class="hljs-function"><span class="hljs-params">ReactElement</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> [tuple, ...restComponent] = components;
    <span class="hljs-keyword">const</span> [Component, componentProps = {}] = tuple <span class="hljs-keyword">as</span> FlatedItem;

    <span class="hljs-keyword">if</span> (Component) {
      <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...componentProps</span>}&gt;</span>{renderProvider(restComponent, children)}<span class="hljs-tag">&lt;/<span class="hljs-name">Component</span>&gt;</span></span>;
    }

    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;&gt;</span>{children}<span class="hljs-tag">&lt;/&gt;</span></span>;
  };

  <span class="hljs-keyword">return</span> renderProvider(components, children);
};

<span class="hljs-keyword">const</span> FlatedReact = {
  <span class="hljs-attr">Wrap</span>: Renderer,
  <span class="hljs-attr">Load</span>: makeFlatedItem,
};
</code></pre>
<h3 id="heading-simplified-usage">Simplified Usage</h3>
<p>The <code>FlatedReact.Load</code> function is not strictly necessary for the functionality but serves an important role for TypeScript type-checking of component props. Heres how you can use FlatedReact to simplify your component structure:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SomeLayoutComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> session = <span class="hljs-keyword">await</span> getServerSession(authOptions);
  <span class="hljs-keyword">const</span> accessToken = <span class="hljs-keyword">await</span> getServerAccessToken();
  <span class="hljs-keyword">const</span> AuthSession = session ? { ...session, accessToken } : session;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FlatedReact.Wrap</span>
      <span class="hljs-attr">components</span>=<span class="hljs-string">{[</span>
        <span class="hljs-attr">FlatedReact.Load</span>(<span class="hljs-attr">TooltipProvider</span>),
        <span class="hljs-attr">FlatedReact.Load</span>(<span class="hljs-attr">AuthProvider</span>, { <span class="hljs-attr">session:</span> <span class="hljs-attr">AuthSession</span> }),
        <span class="hljs-attr">FlatedReact.Load</span>(<span class="hljs-attr">IntercomProvider</span>),
        <span class="hljs-attr">FlatedReact.Load</span>(<span class="hljs-attr">EmailVerificationProvider</span>),
        <span class="hljs-attr">FlatedReact.Load</span>(<span class="hljs-attr">ThemeProvider</span>, {
          <span class="hljs-attr">attribute:</span> '<span class="hljs-attr">class</span>',
          <span class="hljs-attr">defaultTheme:</span> '<span class="hljs-attr">dark</span>',
          <span class="hljs-attr">enableSystem:</span> <span class="hljs-attr">true</span>,
        }),
      ]}
    &gt;</span>
      {/* ...other children */}
    <span class="hljs-tag">&lt;/<span class="hljs-name">FlatedReact.Wrap</span>&gt;</span></span>
  );
}
</code></pre>
<h3 id="heading-typescript-support">Typescript support</h3>
<p>By using <code>FlatedReact.Load</code> function, your IDE and <code>tsc</code> compiler can enforce the right props for the React component. For instance, you can see the following VSCode screenshots for type checking:</p>
<p>Typescript checking:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722170938317/47e26509-beac-491d-b926-6cff1ecc9a22.png" alt="Typescript checking" class="image--center mx-auto" />
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722170927608/677e63f8-5064-4a82-b70b-8fe6cc10765f.png" alt="Typescript checking 2" class="image--center mx-auto" /></p>
<p>Code completion:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722170945791/1a0e5664-fd48-4ae6-8739-aa7b5ed72d2c.png" alt="Code completion" class="image--center mx-auto" /></p>
<h3 id="heading-comparison-with-other-solutions">Comparison with Other Solutions</h3>
<p>I had read some articles that offered different approaches to this problem. One such article was by Alfredo Salzillo, titled <a target="_blank" href="https://dev.to/alfredosalzillo/the-react-context-hell-7p4">The React Context Hell</a>. This approach involved cloning elements but isn't well-supported in TypeScript, and using <code>cloneElement</code> with direct will lead to double renders.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// code from: https://dev.to/alfredosalzillo/the-react-context-hell-7p4</span>
<span class="hljs-comment">// calling `cloneElement` inside MultiProvider will render an other `ReduxProvider` aka call ReduxProvider twice </span>
&lt;MultiProvider
      providers={[
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ReduxProvider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{store}</span> /&gt;</span></span>, 
        <span class="hljs-comment">// ...others, </span>
      ]}
    &gt;
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">HelloWorld</span> /&gt;</span></span>
    &lt;/MultiProvider&gt;
</code></pre>
<p>Another insightful read was <a target="_blank" href="https://medium.com/@ambrosekibet576/navigating-reacts-context-hell-f6f4fe5dc23a">Navigating Reacts Context Hell</a> by Ambrose Kibet. This article suggested moving to a global state, which, while effective in some scenarios, doesn't always work well with large applications or special providers like session providers in Next.js.</p>
<h3 id="heading-versatility-beyond-providers">Versatility Beyond Providers</h3>
<p>An important note is that FlatedReact is not limited to simplifying context providers. It supports any React components nested within each other. This flexibility means that you can use FlatedReact to flatten and manage various component hierarchies, ensuring that your component structure remains clean and maintainable, regardless of the specific components involved.</p>
<h3 id="heading-testing-flatedreact">Testing FlatedReact</h3>
<p>To ensure FlatedReact works as expected, Ive written tests using Jest and React Testing Library. These tests verify that FlatedReact correctly renders nested components and handles different scenarios, such as components with and without props.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { render } <span class="hljs-keyword">from</span> <span class="hljs-string">"@testing-library/react"</span>;
<span class="hljs-keyword">import</span> FlatedReact <span class="hljs-keyword">from</span> <span class="hljs-string">"../dist/cjs"</span>; <span class="hljs-comment">// Adjust the import based on your project structure</span>

<span class="hljs-comment">// Mock components for testing</span>
<span class="hljs-keyword">const</span> MockComponentA: React.FC&lt;
  React.PropsWithChildren&lt;{ <span class="hljs-attr">message</span>: string }&gt;
&gt; = <span class="hljs-function">(<span class="hljs-params">{ message, children }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    A: {message}
    {children}
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);

<span class="hljs-keyword">const</span> MockComponentB: React.FC&lt;React.PropsWithChildren&lt;{ <span class="hljs-attr">count</span>: number }&gt;&gt; = <span class="hljs-function">(<span class="hljs-params">{
  count,
  children,
}</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    B: {count}
    {children}
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);

<span class="hljs-keyword">let</span> componentCIndex = <span class="hljs-number">0</span>;
<span class="hljs-keyword">const</span> MockComponentC: React.FC&lt;React.PropsWithChildren&gt; = <span class="hljs-function">(<span class="hljs-params">{ children }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    C: {++componentCIndex}
    {children}
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);

describe(<span class="hljs-string">"FlatedReact"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"renders nested components correctly"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { queryAllByLabelText, container } = render(
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FlatedReact.Wrap</span>
        <span class="hljs-attr">components</span>=<span class="hljs-string">{[</span>
          <span class="hljs-attr">FlatedReact.Load</span>(<span class="hljs-attr">MockComponentA</span>, { <span class="hljs-attr">message:</span> "<span class="hljs-attr">Hello</span>" }),
          <span class="hljs-attr">FlatedReact.Load</span>(<span class="hljs-attr">MockComponentB</span>, { <span class="hljs-attr">count:</span> <span class="hljs-attr">42</span> }),
          <span class="hljs-attr">MockComponentC</span>,
        ]}
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Children Content<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">FlatedReact.Wrap</span>&gt;</span></span>
    );

    expect(queryAllByLabelText(<span class="hljs-string">"A: Hello"</span>)).toBeTruthy();
    expect(queryAllByLabelText(<span class="hljs-string">"B: 42"</span>)).toBeTruthy();
    expect(queryAllByLabelText(<span class="hljs-string">"C"</span>)).toBeTruthy();
    expect(container).toMatchSnapshot();
  });

  it(<span class="hljs-string">"renders components with default props"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { queryAllByLabelText, container } = render(
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FlatedReact.Wrap</span>
        <span class="hljs-attr">components</span>=<span class="hljs-string">{[</span>
          <span class="hljs-attr">FlatedReact.Load</span>(<span class="hljs-attr">MockComponentA</span>, { <span class="hljs-attr">message:</span> "<span class="hljs-attr">Default</span> <span class="hljs-attr">Message</span>" }),
          <span class="hljs-attr">FlatedReact.Load</span>(<span class="hljs-attr">MockComponentC</span>),
        ]}
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Default Children<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">FlatedReact.Wrap</span>&gt;</span></span>
    );

    expect(queryAllByLabelText(<span class="hljs-string">"A: Default Message"</span>)).toBeTruthy();
    expect(queryAllByLabelText(<span class="hljs-string">"C"</span>)).toBeTruthy();
    expect(queryAllByLabelText(<span class="hljs-string">"Default Children"</span>)).toBeTruthy();
    expect(container).toMatchSnapshot();
  });

  it(<span class="hljs-string">"renders without props and `FlatedReact.Load` correctly"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { queryAllByLabelText, container } = render(
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FlatedReact.Wrap</span>
        <span class="hljs-attr">components</span>=<span class="hljs-string">{[</span>
          <span class="hljs-attr">FlatedReact.Load</span>(<span class="hljs-attr">MockComponentC</span>),
          [<span class="hljs-attr">MockComponentC</span>],
          [<span class="hljs-attr">MockComponentC</span>, <span class="hljs-attr">undefined</span>],
          [<span class="hljs-attr">MockComponentC</span>, <span class="hljs-attr">null</span>],
          [<span class="hljs-attr">MockComponentC</span>, {}],
          <span class="hljs-attr">MockComponentC</span>,
        ]}
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>No Props Children<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">FlatedReact.Wrap</span>&gt;</span></span>
    );

    expect(queryAllByLabelText(<span class="hljs-string">"C"</span>)).toBeTruthy();
    expect(queryAllByLabelText(<span class="hljs-string">"No Props Children"</span>)).toBeTruthy();
    expect(container).toMatchSnapshot();
  });
});
</code></pre>
<h3 id="heading-testing-flatedreact-1">Testing FlatedReact</h3>
<ul>
<li><p>GitHub Repository:</p>
<blockquote>
<p>Explore the code and contribute to the FlatedReact project on GitHub: <a target="_blank" href="https://github.com/cute-me-on-repos/flated-react">FlatedReact on GitHub</a>.</p>
</blockquote>
</li>
<li><p>NPM Package:</p>
<blockquote>
<p>Install FlatedReact and view detailed documentation: <a target="_blank" href="https://www.npmjs.com/package/@cute-me-on-repos/flated-react">FlatedReact on NPM</a>.</p>
</blockquote>
</li>
<li><p>Articles that Inspired the Solution:</p>
<ul>
<li><p><a target="_blank" href="https://dev.to/alfredosalzillo/the-react-context-hell-7p4">The React Context Hell</a> by Alfredo Salzillo.</p>
</li>
<li><p><a target="_blank" href="https://medium.com/@ambrosekibet576/navigating-reacts-context-hell-f6f4fe5dc23a">Navigating Reacts Context Hell</a> by Ambrose Kibet</p>
</li>
</ul>
</li>
</ul>
<p>These resources provide further insight into the challenges of nested React contexts and the different approaches to addressing them, highlighting why FlatedReact offers a more streamlined and TypeScript-friendly solution.</p>
<hr />
<p>I created FlatedReact to share a utility that flattens the provider structure, making it more readable and maintainable. By leveraging TypeScript and React's powerful composition capabilities, FlatedReact helps streamline multiple context providers' setup, transforming how we manage global states in React applications.</p>
]]></description><link>https://thediligentengineer.com/the-flated-reaction</link><guid isPermaLink="true">https://thediligentengineer.com/the-flated-reaction</guid><category><![CDATA[react-context-hell]]></category><category><![CDATA[React]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[callback hell ]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[The Art of Asking Smarter Questions]]></title><description><![CDATA[<blockquote>
<p>After watching <a target="_blank" href="https://www.youtube.com/watch?v=_ILCCMbhCW4">Chloe's YouTube video</a> on this topic, I decided to write this post as a write-up to take notes about what she shared and what makes me interested.</p>
</blockquote>
<p>In today's fast-paced world, the ability to ask the right questions is becoming increasingly important, especially in leadership roles. As an engineer, understanding and applying the art of asking smarter questions can significantly impact our problem-solving abilities and strategic decision-making processes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720955946416/884684f0-c703-4281-bf1c-977272277cbb.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-shift-from-answers-to-questions">The Shift from Answers to Questions</h2>
<p>Traditionally, the focus has been on having the right answers. However, advancements in technology and the complexity of modern problems necessitate a shift towards prioritizing the right questions. This transition is crucial for developing innovative solutions and ensuring robust strategies in the face of evolving challenges.</p>
<h2 id="heading-categories-of-strategic-questions">Categories of Strategic Questions</h2>
<p>According to a study by IMD Business School, as highlighted in the Harvard Business Review article "The Art of Asking Smarter Questions," strategic questions can be categorized into five main types: investigative, speculative, productive, interpretive, and subjective. Each category serves a unique purpose in the decision-making process.</p>
<h3 id="heading-investigative-questions">Investigative Questions</h3>
<p>These questions, such as "What do we know?", help in identifying and clarifying existing information. For instance, the failure of the French railway company SNCF to account for the dimensions of regional train stations while purchasing new trains led to significant financial and operational setbacks. Investigative questions would have highlighted these critical details early on, preventing costly mistakes (<a target="_blank" href="https://www.railway-technology.com/news/newsfrances-sncf-orders-2000-new-trains-that-are-too-wide-4274382/">Railway Technology</a>) (<a target="_blank" href="https://www.huffingtonpost.co.uk/2014/05/21/trains-too-wide-for-platforms_n_5363781.html">HuffPost UK</a>).</p>
<h3 id="heading-speculative-questions">Speculative Questions</h3>
<p>Speculative questions, like "What if?", allow leaders to explore different scenarios and potential outcomes. When a team lacks motivation, asking "What if we organize a retreat?" versus "What if we replace the team members?" can lead to vastly different strategies with distinct implications for team morale and project success.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720955977054/9f1e0593-f1b5-4b7e-bb4e-4a1c454d65aa.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-productive-questions">Productive Questions</h3>
<p>Productive questions focus on implementation and efficiency. Examples include "How can we get it done?" and "How will we measure progress?". The LEGO Group's experience in the early 2000s serves as a cautionary tale. Rapid diversification without considering resource alignment and performance metrics led to substantial losses. Productive questions could have ensured better synchronization and tracking of initiatives.</p>
<h3 id="heading-interpretive-questions">Interpretive Questions</h3>
<p>Interpretive questions, such as "So what?", help in understanding the deeper implications of findings and ideas. For example, during the development of a new electric vehicle, Teslas engineers could have benefited from asking interpretive questions to foresee the long-term impact and market potential, rather than focusing solely on technical flaws.</p>
<h3 id="heading-subjective-questions">Subjective Questions</h3>
<p>Subjective questions, like "Whats unsaid?", address personal and emotional factors that might affect decision-making. The British Airways rebranding effort in 1997 ignored employee and customer sentiments, leading to dissatisfaction and brand disloyalty. Acknowledging these subjective elements could have guided more inclusive and effective strategies.</p>
<h2 id="heading-balancing-question-types-for-effective-leadership">Balancing Question Types for Effective Leadership</h2>
<p>To become more effective decision-makers, it is crucial to balance these types of questions. Assessing one's questioning style, incorporating diverse questions in discussions, and leveraging team strengths to cover blind spots are essential steps.</p>
<p>In conclusion, mastering the art of asking smarter questions can transform how engineers lead and innovate by focusing on the right questions, we can uncover deeper insights, develop more strategic solutions, and drive meaningful progress in our projects and organizations.</p>
<p>For more insights, you can look see the following references on this topic.</p>
<h2 id="heading-references">References</h2>
<ul>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=_ILCCMbhCW4">Chloe's YouTube video</a> on this topic (in Vietnamese).</p>
</li>
<li><p><a target="_blank" href="https://hbr.org/2024/05/the-art-of-asking-smarter-questions">The Art of Asking Smarter Questions, Harvard Business Review</a></p>
</li>
<li><p><strong>SNCF Train Dimensions Mistake</strong>:</p>
<ul>
<li>French railway operator SNCF ordered new trains that were too wide for many regional platforms due to incorrect dimensions provided by RFF. The error, discovered after the order, resulted in a costly modification of platforms to accommodate the trains (<a target="_blank" href="https://www.railway-technology.com/news/newsfrances-sncf-orders-2000-new-trains-that-are-too-wide-4274382/">Railway Technology</a>) (<a target="_blank" href="https://www.huffingtonpost.co.uk/2014/05/21/trains-too-wide-for-platforms_n_5363781.html">HuffPost UK</a>).</li>
</ul>
</li>
<li><p><strong>NASA Metric Conversion Error</strong>:</p>
<ul>
<li>NASA's $125 million Mars Climate Orbiter was lost in 1999 due to a metric conversion error. Engineers at Lockheed Martin used imperial units instead of metric units, leading to the spacecraft's incorrect trajectory and subsequent destruction in the Martian atmosphere (<a target="_blank" href="https://www.washingtonpost.com/wp-srv/national/longterm/space/stories/orbiter100199.htm#:~:text=NASA's%20Mars%20Climate%20Orbiter%20was,Martian%20surface%2C%20investigators%20said%20yesterday.">WSP</a>).</li>
</ul>
</li>
</ul>
]]></description><link>https://thediligentengineer.com/the-art-of-asking-smarter-questions</link><guid isPermaLink="true">https://thediligentengineer.com/the-art-of-asking-smarter-questions</guid><category><![CDATA[#PromptEngineering]]></category><category><![CDATA[prompting]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Recap: Optimization, Fault Tolerance and Distributed Transactions with Node.js GraphQL Servers]]></title><description><![CDATA[<p>As I wrap up my journey at Groove Technology, I had the opportunity to share insights and advancements in optimizing and ensuring fault tolerance in Node.js GraphQL servers. My presentation, held on June 27, 2024, encapsulated the hard work and dedication of the team, highlighting key strategies and implementations that have significantly enhanced server performance and reliability.</p>
<h4 id="heading-introduction"><strong>Introduction</strong></h4>
<p>Pushing the boundaries of what's possible with Node.js and GraphQL has always been a priority. As many know, Node.js is a powerful, open-source, cross-platform JavaScript runtime environment, while GraphQL is a versatile data query and manipulation language for APIs. These tools have been central to the tech stack, enabling the building of efficient and scalable applications.</p>
<p><strong>Optimization</strong> and <strong>fault tolerance</strong> have been guiding principles. Optimization focuses on refining software to achieve maximum efficiency and performance, while fault tolerance ensures systems remain robust and reliable even in the face of failures.</p>
<h4 id="heading-optimization-techniques"><strong>Optimization Techniques</strong></h4>
<p>During the presentation, I delved into several key optimization techniques implemented in projects:</p>
<ol>
<li><p><strong>GraphQL Field Loader</strong>:</p>
<ul>
<li>This tool has been a game-changer, optimizing data fetching by batching queries and minimizing database round-trips. By conditionally executing the field loader based on client queries, significant reductions in latency and overall improvements in server performance have been achieved.</li>
</ul>
</li>
<li><p><strong>Cancelable GraphQL Resolver/Circuit Breaker</strong>:</p>
<ul>
<li>To enhance the reliability of GraphQL resolvers, the CancelableCircuitBreaker class was introduced. This allows for the management of timeouts, handling client disconnections, and incorporating external cancellation signals. These features prevent long-running operations from hanging and efficiently manage resources during request cancellations.</li>
</ul>
</li>
<li><p><strong>Observer Pattern</strong>:</p>
<ul>
<li>Re-implemented using vanilla TypeScript, the Observer pattern has helped manage multiple values emitters more effectively, showcasing the power and flexibility of TypeScript in the development process.</li>
</ul>
</li>
<li><p><strong>Converting CPU Intensive Tasks to Node.js C++ Addons</strong>:</p>
<ul>
<li>By offloading CPU-intensive tasks to more efficient C++ code, remarkable improvements in performance have been achieved. The step-by-step process of creating and compiling Node.js C++ addons was a highlight, demonstrating the tangible benefits of this approach.</li>
</ul>
</li>
</ol>
<h4 id="heading-fault-tolerance-mechanisms"><strong>Fault Tolerance Mechanisms</strong></h4>
<p>Ensuring that systems remain operational and reliable in the face of unexpected issues is critical. Here are the fault tolerance mechanisms discussed:</p>
<ol>
<li><p><strong>Graceful Shutdown</strong>:</p>
<ul>
<li>This technique ensures ongoing operations are completed, connections are closed gracefully, and data integrity is maintained. It's a crucial practice for minimizing downtime and avoiding data loss during server shutdowns.</li>
</ul>
</li>
<li><p><strong>Distributed Transactions</strong>:</p>
<ul>
<li><p>Managing operations across multiple data repositories can be complex. Two main strategies were explored:</p>
<ul>
<li><p><strong>Two-Phase Commit (2PC)</strong>: Ensures atomicity across multiple databases or services. While it guarantees consistency, it can lead to blocking issues and scalability concerns.</p>
</li>
<li><p><strong>Saga Pattern</strong>: An alternative approach that manages distributed transactions asynchronously. It breaks down transactions into smaller, independently manageable parts, providing better scalability and gracefully handling failures.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Distributed Locks with Redis</strong>:</p>
<ul>
<li>To synchronize access to shared resources in a distributed system, Redis-based locking mechanisms were implemented, ensuring smooth and coordinated resource management.</li>
</ul>
</li>
</ol>
<p><strong>Links and References</strong>:</p>
<ul>
<li><p><a target="_blank" href="https://dzone.com/articles/distributed-lock-implementation-with-redis">Distributed Lock Implementation with Redis</a></p>
</li>
<li><p><a target="_blank" href="https://www.geeksforgeeks.org/two-phase-commit-protocol-distributed-transaction-management/">Two-Phase Commit Protocol</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/architecture/reference-architectures/saga/saga">Saga Pattern Reference Architecture</a></p>
</li>
<li><p><a target="_blank" href="https://gist.github.com/lyluongthien/4dceaa3e589939da554b70633331428c">Codes on Gist</a></p>
</li>
<li><p><a target="_blank" href="https://www.slideshare.net/slideshow/optimization-and-fault-tolerance-in-distributed-transaction-with-node-js-graphql-servers/269936567">Slideshare</a></p>
</li>
</ul>
<h4 id="heading-disclaimer"><strong>Disclaimer</strong></h4>
<p>This article is partially generated by GPT-4o.</p>
<h4 id="heading-conclusion-and-reflection"><strong>Conclusion and Reflection</strong></h4>
<p>As I move on from Groove Technology, I'm filled witha sense of pride and accomplishment. The advancements in optimizing and ensuring the fault tolerance of Node.js GraphQL servers are a testament to the hard work and ingenuity of the team. This presentation was not just a summary of technical achievements but a celebration of the collaborative spirit and innovation that define Groove Technology.</p>
<p>I'm grateful for the experiences and opportunities had here and excited for the future. I look forward to seeing how these implementations continue to evolve and contribute to the success of Groove Technology.</p>
<p>Thank you to everyone who attended the presentation and for your continued support and enthusiasm. Let's keep pushing the boundaries and making great things happen!</p>
<p>Warm regards,</p>
<p><strong>Kai</strong></p>
]]></description><link>https://thediligentengineer.com/recap-optimization-fault-tolerance-and-distributed-transactions-with-nodejs-graphql-servers</link><guid isPermaLink="true">https://thediligentengineer.com/recap-optimization-fault-tolerance-and-distributed-transactions-with-nodejs-graphql-servers</guid><category><![CDATA[fault tolerance]]></category><category><![CDATA[distributed system]]></category><category><![CDATA[transactions]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[GraphQL]]></category><category><![CDATA[presentations]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Recap: Integrate Email Testing Service: Inbucket from Development to integration testing]]></title><description><![CDATA[<p>On June 26, 2023, during my final working week at Groove Technology, I had the pleasure of delivering a presentation on integrating Inbucket into development workflows for comprehensive email testing. For those who couldn't attend, heres a detailed recap of the key points I covered in the presentation.</p>
<p><strong>What is Inbucket?</strong></p>
<p>Inbucket is a powerful, open-source email testing tool that allows developers to view the emailed output of their applications quickly and efficiently. Unlike hosted services such as Mailinator, Inbucket can be run lightly on your own private network or desktop, providing a secure and customizable solution for email testing needs.</p>
<p><strong>Why Inbucket?</strong></p>
<p>Inbucket offers numerous benefits that make it an essential tool for modern development workflows:</p>
<ul>
<li><p><strong>No Per-Account Setup:</strong> Inbucket creates mailboxes on the fly as mail is received, eliminating the need for manual setup.</p>
</li>
<li><p><strong>Built-in Servers:</strong> With built-in SMTP and POP3 servers, Inbucket stores incoming mail as flat files on disk, requiring no external SMTP or database services.</p>
</li>
<li><p><strong>User-Friendly Web Interface:</strong> Easily view and manage emails through a comprehensive web interface.</p>
</li>
<li><p><strong>Open Source:</strong> Written in Go and Elm, Inbucket is open-source software released under the MIT License, allowing for extensive customization and community support.</p>
</li>
</ul>
<p><strong>Fun fact:</strong> <a target="_blank" href="https://supabase.com/docs/guides/cli/testing-and-linting"><strong><em>Supabase</em></strong></a> <strong><em>is using Inbucket for their local development CLI</em></strong></p>
<p><strong>Presentation Highlights</strong></p>
<p>During the presentation, I covered a range of topics to help the audience understand and implement Inbucket in their development and testing environments:</p>
<ol>
<li><p><strong>Introduction to Inbucket</strong></p>
<ul>
<li><p>Overview of its features and benefits</p>
</li>
<li><p>Comparison with other email testing services</p>
</li>
</ul>
</li>
<li><p><strong>Technical Overview</strong></p>
<ul>
<li><p>Architecture and APIv1</p>
</li>
<li><p>How Inbucket stores emails</p>
</li>
</ul>
</li>
<li><p><strong>Implementation in Software Development</strong></p>
<ul>
<li><p>Step-by-step setup and installation</p>
</li>
<li><p>Integration with development servers and internal project</p>
</li>
</ul>
</li>
<li><p><strong>Demo: Integrating Inbucket with a Development Server (to an internal project)</strong></p>
<ul>
<li><p>Real-time demonstration of setup and integration</p>
</li>
<li><p>Sending test emails and viewing them in the Inbucket web interface</p>
</li>
</ul>
</li>
<li><p><strong>Demo: Utilizing Inbucket in Integration Testing</strong></p>
<ul>
<li><p>Integrating Inbucket into testing workflow</p>
</li>
<li><p>Automating tests and improving email verification processes</p>
</li>
<li><p>Addition e2e setup</p>
</li>
</ul>
</li>
<li><p><strong>Demo: Writing an Inbucket client that supports real-time email observer</strong></p>
<ul>
<li><p>Opensource at: <a target="_blank" href="http://github.com/groovetch/inbucket-gt-client"><strong>github.com/groovetch/inbucket-gt-client</strong></a></p>
</li>
<li><p>NPM package: <a target="_blank" href="https://www.npmjs.com/package/@cute-me-on-repos/inbucket-gt-client"><strong>npmjs.com/package/@cute-me-on-repos/inbucket-gt-client</strong></a></p>
</li>
</ul>
</li>
</ol>
<p><strong>Why Inbucket is Essential</strong></p>
<p>I emphasized the importance of efficient email testing in modern development workflows. With Inbucket, developers can streamline their email testing processes, ensuring email functionalities are thoroughly tested and verified before deployment. This leads to improved quality control and a more reliable end product.</p>
<p><strong>Conclusion</strong></p>
<p>Delivering this presentation was a fitting end to my tenure at Groove Technology, leaving my colleagues with practical knowledge and tools to enhance their email testing processes. I am excited to see how Inbucket will be integrated into our workflows and look forward to the improvements it will bring.</p>
<p>Stay tuned for more updates and resources on Inbucket and other innovative tools to optimize your development and testing workflows!</p>
<p>Links:</p>
<ul>
<li><p>Inbucket: <a target="_blank" href="https://inbucket.org/">https://inbucket.org</a></p>
</li>
<li><p>Inbucket Github: <a target="_blank" href="https://github.com/inbucket">https://github.com/inbucket</a></p>
</li>
<li><p>My Opensource Inbucket Client: <a target="_blank" href="http://github.com/cute-me-on-repos/inbucket-gt-client"><strong>github.com/cute-me-on-repos/inbucket-gt-client</strong></a></p>
</li>
<li><p>My NPM package: <a target="_blank" href="https://www.npmjs.com/package/@cute-me-on-repos/inbucket-gt-client"><strong>npmjs.com/package/@cute-me-on-repos/inbucket-gt-client</strong></a></p>
</li>
<li><p>Slideshare: <a target="_blank" href="https://www.slideshare.net/slideshow/integrate-email-testing-service-inbucket-from-development-to-integration-testing/269897336">https://www.slideshare.net/slideshow/integrate-email-testing-service-inbucket-from-development-to-integration-testing/269897336</a></p>
</li>
</ul>
]]></description><link>https://thediligentengineer.com/recap-inbucket-presentation</link><guid isPermaLink="true">https://thediligentengineer.com/recap-inbucket-presentation</guid><category><![CDATA[inbucket]]></category><category><![CDATA[mailserver]]></category><category><![CDATA[integration]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Introduction to the new thread-safe event package for Golang]]></title><description><![CDATA[<p>Events are a common pattern in many applications, especially those that involve user interactions, asynchronous operations, or communication between different components. Events allow you to decouple the logic of the event source from the logic of the event listeners, making your code more modular, reusable, and testable.</p>
<p>However, managing events and listeners in Go can be tricky, especially when concurrency is involved. You need to ensure that your event channels are properly created, closed, and buffered, and that your listeners are registered and unregistered correctly. You also need to handle any errors or panics that may occur during the event processing.</p>
<p>That's why we created the new <a target="_blank" href="https://pkg.go.dev/github.com/lltpkg/event">event</a> package, a simple and thread-safe mechanism for managing events and listeners in Go applications. The event package provides a high-level API that abstracts away the low-level details of creating and managing event channels and listeners. It also handles any errors or panics gracefully, ensuring that your application does not crash or leak resources.</p>
<h2 id="heading-installation">Installation</h2>
<p>To use the event package in your Go project, you can use the following go get command:</p>
<pre><code class="lang-bash">go get -u github.com/lltpkg/event
</code></pre>
<h2 id="heading-quick-start">Quick start</h2>
<p>To get started with the event package, you need to import it in your Go file:</p>
<pre><code class="lang-go"><span class="hljs-keyword">import</span> <span class="hljs-string">"github.com/lltpkg/event"</span>
</code></pre>
<p>Then, you can create an event channel and a listener for any event name you want. For example, let's create an event channel and a listener for the "Greeting" event:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
<span class="hljs-string">"fmt"</span>

<span class="hljs-string">"github.com/lltpkg/event"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
<span class="hljs-comment">// Create an event channel and a cleanup function for the "Greeting" event</span>
evChan, cleanup := event.EventChannel(<span class="hljs-string">"Greeting"</span>)
<span class="hljs-comment">// Make sure to call the cleanup function when done</span>
<span class="hljs-keyword">defer</span> cleanup()

<span class="hljs-comment">// Listen for the "Greeting" event in a goroutine</span>
<span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
<span class="hljs-comment">// Receive the event data from the channel</span>
receivedData := &lt;-evChan
<span class="hljs-comment">// Print the greeting message</span>
fmt.Println(<span class="hljs-string">"Hello,"</span>, receivedData)
}()

<span class="hljs-comment">// Trigger the "Greeting" event with some data</span>
event.FireEvent(<span class="hljs-string">"Greeting"</span>, <span class="hljs-string">"World"</span>)
}
</code></pre>
<p>If you run this code, you should see the following output:</p>
<pre><code class="lang-txt">Hello, World
</code></pre>
<p>As you can see, the event package makes it easy to create and use event channels and listeners in Go. You don't need to worry about creating, closing, or buffering the channels, or registering or unregistering the listeners. The event package takes care of all that for you.</p>
<h2 id="heading-usage">Usage</h2>
<p>Creating Events and Listeners
The event package allows you to create named events and associate listeners with them. You can use the EventChannel function to create an event channel and a cleanup function for any event name:</p>
<pre><code class="lang-go"><span class="hljs-comment">// Create an event channel and a cleanup function for "exampleEvent"</span>
eventChan, cleanup := event.EventChannel(<span class="hljs-string">"exampleEvent"</span>)
<span class="hljs-comment">// Make sure to call the cleanup function when done</span>
<span class="hljs-keyword">defer</span> cleanup()
</code></pre>
<p>The event channel is a chan interface{} that receives the event data whenever the event is triggered. The cleanup function is a func() that closes the event channel and unregisters the listener from the event. You should always call the cleanup function when you are done with the event channel, otherwise you may leak resources or cause deadlocks.</p>
<p>You can create as many event channels and listeners as you want for the same or different event names. The event package will ensure that each listener receives the event data in a thread-safe manner.</p>
<h2 id="heading-triggering-events">Triggering Events</h2>
<p>You can trigger events using the FireEvent function. This function allows you to send data to all registered listeners for a specific event name:</p>
<pre><code class="lang-go"><span class="hljs-comment">// Trigger the "exampleEvent" with some data</span>
event.FireEvent(<span class="hljs-string">"exampleEvent"</span>, <span class="hljs-string">"event data"</span>)
</code></pre>
<p>The data can be any value that implements the <code>interface{}</code> type. The <code>FireEvent</code> function will send the data to all the event channels that are listening for the event name. The function will also handle any errors or panics that may occur during the event processing, and log them using the standard log package.</p>
<p>You can trigger events from anywhere in your code, as long as you import the event package. The <code>FireEvent</code> function is thread-safe and non-blocking, so you can use it in concurrent or asynchronous contexts.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We hope that you find the event package useful and easy to use. If you have any feedback, suggestions, or issues, please feel free to open an issue or a pull request on the <a target="_blank" href="https://github.com/lltpkg/event">GitHub repository</a>. We appreciate any contributions that make the event package more robust and versatile.</p>
]]></description><link>https://thediligentengineer.com/introduction-to-the-new-thread-safe-event-package-for-golang</link><guid isPermaLink="true">https://thediligentengineer.com/introduction-to-the-new-thread-safe-event-package-for-golang</guid><category><![CDATA[Go Language]]></category><category><![CDATA[package]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[A note on TypeScript discrimination unions]]></title><description><![CDATA[<p>Recently I started using discrimination unions a lot in typescript.
This technique allows us to write more type-safe codes, for instance:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Bird {
  name: <span class="hljs-string">"bird"</span>,
  fly(): <span class="hljs-built_in">void</span>;
  layEggs(): <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">interface</span> Fish {
  name: <span class="hljs-string">"fish"</span>,
  swim(): <span class="hljs-built_in">void</span>;
  layEggs(): <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSmallPet</span>(<span class="hljs-params"></span>): <span class="hljs-title">Fish</span> | <span class="hljs-title">Bird</span></span>;

<span class="hljs-keyword">let</span> pet = getSmallPet();
</code></pre>
<p>This works:</p>
<pre><code class="lang-js">pet.layEggs();
</code></pre>
<p>But not this:</p>
<pre><code class="lang-js">pet.swim(); 
<span class="hljs-comment">// Errors in code:</span>
<span class="hljs-comment">// Property 'swim' does not exist on type 'Bird | Fish'.</span>
<span class="hljs-comment">//   Property 'swim' does not exist on type 'Bird'.</span>
</code></pre>
<p>This forces us to add additional checks to pass the compiler error:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">if</span>(pet.name === <span class="hljs-string">'fish'</span>){
  pet.swim(); <span class="hljs-comment">// this will work</span>
}
</code></pre>
<p> See more on <a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions">typescriptlang.org/docs</a> </p>
]]></description><link>https://thediligentengineer.com/a-note-on-typescript-discrimination-unions</link><guid isPermaLink="true">https://thediligentengineer.com/a-note-on-typescript-discrimination-unions</guid><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Write an O(m*n) LeetCode solution of find-and-replace-pattern that beats 100.00% of users with TypeScript [54ms]]]></title><description><![CDATA[<blockquote>
<p>Try to solve the solution before read this article at: <a target="_blank" href="https://leetcode.com/problems/find-and-replace-pattern">leetcode.com/problems/find-and-replace-pattern</a></p>
</blockquote>
<h1 id="heading-intuition">Intuition</h1>

<p><strong>Thoughts</strong>:</p>
<ul>
<li>Focus on matching patterns, not exact characters. The problem doesn't require matching exact characters, but rather identifying words that follow the same pattern as the given pattern string.</li>
<li>Character consistency is crucial. A word matches the pattern if we can consistently replace each character in the pattern with a unique character in the word, and vice versa.</li>
</ul>
<h1 id="heading-approach">Approach</h1>

<ol>
<li><p>Transform Words and Pattern:</p>
<ul>
<li>Create a function <code>wordToId</code> that transforms a word into a pattern-like string:<ul>
<li>It assigns a unique integer ID to each distinct character in the word.</li>
<li>It joins these IDs using hyphens to create a pattern-like representation.</li>
</ul>
</li>
<li>Apply <code>wordToId</code> to both the <code>pattern</code> and each word in the <code>words</code> array.</li>
</ul>
</li>
<li><p>Identify Matching Words:</p>
<ul>
<li>Iterate through each word in the <code>words</code> array.</li>
<li>If the transformed pattern-like string of the word matches the transformed <code>pattern</code>, add the original word to the <code>result</code> array.</li>
</ul>
</li>
<li><p>Return Matching Words:</p>
<ul>
<li>Return the <code>result</code> array containing the words that match the pattern.</li>
</ul>
</li>
</ol>
<h1 id="heading-complexity">Complexity</h1>
<ul>
<li>Time complexity: O(n * m), where n is the number of words in the <code>words</code> array and m is the length of each word (and the <code>pattern</code>). This is due to iterating through each word and transforming it character by character.</li>
<li>Space complexity: O(m), where m is the length of the words and pattern. The space used is primarily for the hash map in <code>wordToId</code> and the transformed strings.</li>
</ul>
<h1 id="heading-flow">Flow</h1>
<pre><code class="lang-mermaid">graph TD
subgraph "findAndReplacePattern function"
    Start("Start") --&gt; Transform["Transform pattern using wordToId"]
        Transform --&gt; Iterate["Iterate through words array"]
        Iterate --Check if word length matches pattern length--&gt; CheckLength{"Check length"}
        CheckLength -- No --&gt; End("End")
        CheckLength -- Yes --&gt; Transform2["Transform word using wordToId"]
        Transform2 --"Compare transformed word with pattern"--&gt; Compare{"Compare pattern"}
        Compare -- No --&gt; Iterate
        Compare -- Yes --&gt; AddToResult["Add word to result array"]
        AddToResult --&gt; Iterate
    End(End)
end
</code></pre>
<h1 id="heading-code">Code</h1>
<h2 id="heading-typescript">TypeScript</h2>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findAndReplacePattern</span>(<span class="hljs-params">words: <span class="hljs-built_in">string</span>[], pattern: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">string</span>[] </span>{
  <span class="hljs-keyword">const</span> result: <span class="hljs-built_in">string</span>[] = [];
  <span class="hljs-keyword">const</span> wordToId = (<span class="hljs-function">(<span class="hljs-params">w: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> idGetter = {
      hMap: {} <span class="hljs-keyword">as</span> Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">number</span>&gt;,
      id: <span class="hljs-number">0</span>,
      getId() {
        <span class="hljs-keyword">return</span> ++<span class="hljs-built_in">this</span>.id
      },
      reset() {
        <span class="hljs-built_in">this</span>.id = <span class="hljs-number">0</span>
        <span class="hljs-built_in">this</span>.hMap = {}
      }
    }
    <span class="hljs-keyword">return</span> [...w].map(<span class="hljs-function"><span class="hljs-params">c</span> =&gt;</span> {
      <span class="hljs-keyword">if</span> (idGetter.hMap[c]) {
        <span class="hljs-keyword">return</span> idGetter.hMap[c]
      } <span class="hljs-keyword">else</span> {
        idGetter.hMap[c] = idGetter.getId()
        <span class="hljs-keyword">return</span> idGetter.hMap[c]
      }
    }).join(<span class="hljs-string">'-'</span>)
  })
  <span class="hljs-keyword">const</span> p = wordToId(pattern)
  words.forEach(<span class="hljs-function"><span class="hljs-params">w</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (w.length !== pattern.length) <span class="hljs-keyword">return</span>
    <span class="hljs-keyword">const</span> id = wordToId(w) 
    <span class="hljs-keyword">if</span> (p === id) {
      result.push(w)
    }
  })

  <span class="hljs-keyword">return</span> result
};
</code></pre>
<h2 id="heading-rust">Rust</h2>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::collections::HashMap;

<span class="hljs-keyword">impl</span> Solution {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">find_and_replace_pattern</span></span>(words: <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">String</span>&gt;, pattern: <span class="hljs-built_in">String</span>) -&gt; <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> result = <span class="hljs-built_in">Vec</span>::new();

        <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">hash_word</span></span>(w: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">String</span> {
            <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> char_to_id = HashMap::new();
            <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> id = <span class="hljs-number">0</span>;
            w.chars().map(|c| {
                *char_to_id.entry(c).or_insert_with(|| { id += <span class="hljs-number">1</span>; id })
            }).map(|id| id.to_string()).collect::&lt;<span class="hljs-built_in">Vec</span>&lt;_&gt;&gt;().join(<span class="hljs-string">"-"</span>)
        }

        <span class="hljs-keyword">let</span> p = hash_word(&amp;pattern);

        <span class="hljs-keyword">for</span> w <span class="hljs-keyword">in</span> words.iter() {
            <span class="hljs-keyword">if</span> w.len() != pattern.len() {
                <span class="hljs-keyword">continue</span>;
            }
            <span class="hljs-keyword">if</span> p == hash_word(w) {
                result.push(w.clone());
            }
        }

        result

    }
}
</code></pre>
<h2 id="heading-golang">Golang</h2>
<pre><code class="lang-golang"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">findAndReplacePattern</span><span class="hljs-params">(words []<span class="hljs-keyword">string</span>, pattern <span class="hljs-keyword">string</span>)</span> []<span class="hljs-title">string</span></span> {
    result := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">string</span>, <span class="hljs-number">0</span>)
    hashWord := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(w <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">string</span></span> {
        hMap := <span class="hljs-keyword">map</span>[<span class="hljs-keyword">rune</span>]<span class="hljs-keyword">int</span>{}
        id := <span class="hljs-number">0</span>
        hashed := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">string</span>, <span class="hljs-number">0</span>, <span class="hljs-built_in">len</span>(w))
        <span class="hljs-keyword">for</span> _, c := <span class="hljs-keyword">range</span> w {
            <span class="hljs-keyword">if</span> _, ok := hMap[c]; !ok {
                hMap[c] = id
                id++
            }
            hashed = <span class="hljs-built_in">append</span>(hashed, strconv.Itoa(hMap[c]))
        }
        <span class="hljs-keyword">return</span> strings.Join(hashed, <span class="hljs-string">"-"</span>)
    }
    p := hashWord(pattern)
    <span class="hljs-keyword">for</span> _, w := <span class="hljs-keyword">range</span> words {
        <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(w) != <span class="hljs-built_in">len</span>(pattern) {
            <span class="hljs-keyword">continue</span>
        }
        <span class="hljs-keyword">if</span> p == hashWord(w) {
            result = <span class="hljs-built_in">append</span>(result, w)
        }
    }
    <span class="hljs-keyword">return</span> result
}
</code></pre>
<h1 id="heading-reference">Reference</h1>
<p>LeetCode submissions: <a target="_blank" href="https://leetcode.com/problems/find-and-replace-pattern/submissions/1133020282/">TypeScript</a>,  <a target="_blank" href="https://leetcode.com/submissions/detail/1133316594/">Rust</a>,  <a target="_blank" href="https://leetcode.com/submissions/detail/1133315776/">Golang</a>.</p>
]]></description><link>https://thediligentengineer.com/write-a-find-and-replace-pattern-leetcode-solution-that-beats-10000-of-users-with-typescript-54ms</link><guid isPermaLink="true">https://thediligentengineer.com/write-a-find-and-replace-pattern-leetcode-solution-that-beats-10000-of-users-with-typescript-54ms</guid><category><![CDATA[leetcode]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Rust]]></category><category><![CDATA[Go Language]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Inlining in Go]]></title><description><![CDATA[<p>The process of grouping smaller functions into their respective callers in Go Compiler is known as inlining. This optimization was often done by hand in the early days of computing. Inlining is now one of the essential optimizations that are executed automatically throughout the compilation process.</p>
<h2 id="heading-the-mechanism">The Mechanism</h2>
<p>Function Identification: The compiler scans your code, identifying functions suitable for inlining. It prioritizes smaller, frequently called functions with simple bodies.</p>
<p>Eliminating Overhead: Instead of generating a separate function call, the compiler replaces the call with the function's code, removing the overhead of:</p>
<ul>
<li>Jumping to a different memory location</li>
<li>Passing arguments</li>
<li>Returning results</li>
</ul>
<p>Code Integration: The inlined function's code is seamlessly integrated into the caller's code, creating a single, streamlined block.</p>
<h2 id="heading-advantages-of-inlining">Advantages of Inlining</h2>
<ul>
<li>Performance Boost:<ul>
<li>Reduced function call overhead</li>
<li>Enhanced optimization opportunities</li>
</ul>
</li>
<li>Code Size Reduction: Elimination of redundant code in some cases</li>
<li>Improved Cache Utilization: Better spatial locality of code and data</li>
</ul>
<pre><code class="lang-mermaid">flowchart TB

    X[1. Start compile]
    X--&gt;SC
    F[Executable bin] 

    subgraph SC[Source Code main.go]

        subgraph A[Function main]
            D[function main Body]
        end  

        subgraph B["function a()"]
            C["function a() body"]
        end 
        A--2. Call(1) --&gt;B
        C--3. Append (inlining)--&gt;D

    end
     SC--4. build --&gt; F
</code></pre>
<h2 id="heading-example">Example</h2>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">add</span><span class="hljs-params">(x, y <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
    <span class="hljs-keyword">return</span> x + y
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    result := add(<span class="hljs-number">5</span>, <span class="hljs-number">3</span>) <span class="hljs-comment">// Function call</span>
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>After inlining:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    result := <span class="hljs-number">5</span> + <span class="hljs-number">3</span> <span class="hljs-comment">// Inlined code</span>
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<h2 id="heading-the-go-compilers-inlining-decisions">The Go Compiler's Inlining Decisions</h2>
<ul>
<li>Function Size: Small, focused functions are more likely to be inlined.</li>
<li>Call Frequency: Frequently called functions are prime candidates.</li>
<li>Loop Presence: Functions containing loops are less likely to be inlined.</li>
<li>Closures and Recursion: These complexities can hinder inlining.</li>
</ul>
<h2 id="heading-key-considerations">Key Considerations</h2>
<ul>
<li>Over-inlining: This can lead to larger code size and potential cache misses.</li>
<li>Readability: Excessive inlining can impact code clarity.</li>
<li>Benchmarking: Measure performance gains to ensure effectiveness.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Function inlining is a potent optimization tool in Go, but its judicious application is crucial. Understanding its mechanics and trade-offs empowers you to write efficient and maintainable Go code. By carefully considering function design, profiling performance, and leveraging compiler hints when necessary, you can effectively harness the power of inlining for optimal code execution.</p>
]]></description><link>https://thediligentengineer.com/inlining-in-go</link><guid isPermaLink="true">https://thediligentengineer.com/inlining-in-go</guid><category><![CDATA[Go Language]]></category><category><![CDATA[compiler]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[PostgreSQL-to-Elasticsearch synchronization: Logstash with JDBC input plugin Vs. PGSync]]></title><description><![CDATA[<p>After hours of implementing the PostgreSQL-to-Elasticsearch synchronization service in many different ways, my team and I at <a target="_blank" href="https://www.linkedin.com/company/groove-technology">GT</a> finally decided to use <a target="_blank" href="https://pgsync.com/">PGSync</a>.
Here's a comparison of Logstash with the JDBC input plugin and PGSync for PostgreSQL-to-Elasticsearch synchronization:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Factor</td><td>Logstash with JDBC Input Plugin</td><td>PGSync</td></tr>
</thead>
<tbody>
<tr>
<td>Overview</td><td>General-purpose data pipeline tool with a JDBC plugin for database integration</td><td>Specialized tool for PostgreSQL replication to Elasticsearch</td></tr>
<tr>
<td>Integration</td><td>Connects to various databases, not PostgreSQL-specific</td><td>Optimized for PostgreSQL, leveraging its logical decoding feature</td></tr>
<tr>
<td>Configuration</td><td>Requires defining pipelines and filters for data processing</td><td>Configuration is simpler, focused on replication settings</td></tr>
<tr>
<td>Data Transformation</td><td>Offers extensive filtering and transformation capabilities within pipelines</td><td>Limited to basic filtering and mapping</td></tr>
<tr>
<td>Performance</td><td>Can be slower for large-scale replication due to overhead of pipeline processing</td><td>Generally faster due to direct replication without intermediate processing</td></tr>
<tr>
<td>Scalability</td><td>Can be horizontally scaled by adding more Logstash nodes</td><td>Limited to vertical scaling of a single PGSync instance</td></tr>
<tr>
<td>Error Handling</td><td>Provides mechanisms for retrying failed events and handling errors</td><td>Less robust error handling mechanisms</td></tr>
<tr>
<td>Monitoring</td><td>Integrates with monitoring tools for pipeline visibility</td><td>Limited monitoring capabilities</td></tr>
<tr>
<td>Maintenance</td><td>Requires managing Logstash and its dependencies</td><td>Simpler setup and maintenance</td></tr>
</tbody>
</table>
</div><p>Choosing the right tool depends on your specific needs:</p>
<ul>
<li>If you require extensive data transformation or integration with other data sources, Logstash is a good choice.</li>
<li>If you need high-performance replication with minimal overhead and a PostgreSQL-specific focus, PGSync is a better option.</li>
<li>Consider factors like scalability, error handling, monitoring, and maintenance requirements when deciding.</li>
</ul>
<p>Additional considerations:</p>
<ul>
<li>Logstash offers more flexibility for custom data processing and integration.</li>
<li>PGSync is typically more efficient for large-scale replication.</li>
<li>Both tools can be used in conjunction for more complex scenarios.</li>
</ul>
<p>Recommendations:</p>
<ul>
<li>For basic, high-performance replication, PGSync is often the preferred choice.</li>
<li>For more complex data processing and integration needs, Logstash provides greater capabilities.</li>
<li>Evaluate your specific use case and requirements to determine the best tool.</li>
</ul>
]]></description><link>https://thediligentengineer.com/postgresql-to-elasticsearch-synchronization-logstash-with-jdbc-input-plugin-vs-pgsync</link><guid isPermaLink="true">https://thediligentengineer.com/postgresql-to-elasticsearch-synchronization-logstash-with-jdbc-input-plugin-vs-pgsync</guid><category><![CDATA[elasticsearch]]></category><category><![CDATA[elk]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item><item><title><![CDATA[Streaming Large Files over TCP]]></title><description><![CDATA[<p>When dealing with large files in development, the traditional approach of reading the entire file into memory can lead to memory-related issues. To overcome this challenge, streaming becomes a crucial concept. Streaming involves sending files in smaller, manageable chunks rather than all at once. In this article, we will explore how to implement a file server in Golang that can efficiently stream large files over TCP connections.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703314200867/af224a8a-8929-4558-bb97-fed4cd7d67a6.jpeg" alt="cover image" /></p>
<h2 id="heading-setting-the-stage">Setting the Stage</h2>
<p>Let's begin by understanding the importance of streaming and the pitfalls of loading large files into memory. Loading large files at once can lead to memory exhaustion, especially in scenarios where the file size exceeds available system resources.</p>
<h2 id="heading-building-a-simple-file-server">Building a Simple File Server</h2>
<p>To implement a file server in Golang, we'll leverage the <code>net</code> package for handling network connections and the <code>io</code> package for reading and writing data. Additionally, we'll use a buffer to efficiently store and manage the streaming data.</p>
<pre><code class="lang-go"><span class="hljs-comment">// File Server</span>

<span class="hljs-comment">// Listen for incoming connections</span>
listener, err := net.Listen(<span class="hljs-string">"tcp"</span>, <span class="hljs-string">":8080"</span>)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
    log.Fatal(err)
}

<span class="hljs-keyword">for</span> {
    <span class="hljs-comment">// Accept connection</span>
    conn, err := listener.Accept()
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }

    <span class="hljs-comment">// Handle connection concurrently</span>
    <span class="hljs-keyword">go</span> handleConnection(conn)
}

<span class="hljs-comment">// Handle Connection</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">handleConnection</span><span class="hljs-params">(conn net.Conn)</span></span> {
    <span class="hljs-keyword">defer</span> conn.Close()

    <span class="hljs-comment">// Open the file</span>
    file, err := os.Open(<span class="hljs-string">"largefile.dat"</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }
    <span class="hljs-keyword">defer</span> file.Close()

    <span class="hljs-comment">// Create a buffer for streaming</span>
    buffer := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">byte</span>, <span class="hljs-number">1024</span>)

    <span class="hljs-comment">// Read and stream file data</span>
    <span class="hljs-keyword">for</span> {
        bytesRead, err := file.Read(buffer)
        <span class="hljs-keyword">if</span> err == io.EOF {
            <span class="hljs-keyword">break</span>
        }
        conn.Write(buffer[:bytesRead])
    }
}
</code></pre>
<h2 id="heading-implementing-the-client">Implementing the Client</h2>
<p>Now that we have our file server, let's create a client program that sends a file to the server. We'll use the <code>net</code> and <code>io</code> packages, along with a buffer for efficient data transfer.</p>
<pre><code class="lang-go"><span class="hljs-comment">// File Client</span>

<span class="hljs-comment">// Dial the server</span>
conn, err := net.Dial(<span class="hljs-string">"tcp"</span>, <span class="hljs-string">"localhost:8080"</span>)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
    log.Fatal(err)
}
<span class="hljs-keyword">defer</span> conn.Close()

<span class="hljs-comment">// Open the file to be sent</span>
file, err := os.Open(<span class="hljs-string">"largefile.dat"</span>)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
    log.Fatal(err)
}
<span class="hljs-keyword">defer</span> file.Close()

<span class="hljs-comment">// Create a buffer for streaming</span>
buffer := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">byte</span>, <span class="hljs-number">1024</span>)

<span class="hljs-comment">// Read and send file data</span>
<span class="hljs-keyword">for</span> {
    bytesRead, err := file.Read(buffer)
    <span class="hljs-keyword">if</span> err == io.EOF {
        <span class="hljs-keyword">break</span>
    }
    conn.Write(buffer[:bytesRead])
}
</code></pre>
<h2 id="heading-handling-unknown-file-sizes">Handling Unknown File Sizes</h2>
<p>A common challenge in file streaming is not knowing the size of the file in advance. To address this, we can send the file size as part of the data, allowing the server to anticipate the incoming data and allocate resources accordingly.</p>
<pre><code class="lang-go"><span class="hljs-comment">// Sending File Size</span>

<span class="hljs-comment">// Get file size</span>
fileInfo, err := file.Stat()
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
    log.Fatal(err)
}

<span class="hljs-comment">// Convert file size to bytes</span>
fileSize := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">byte</span>, <span class="hljs-number">8</span>)
binary.BigEndian.PutUint64(fileSize, <span class="hljs-keyword">uint64</span>(fileInfo.Size()))

<span class="hljs-comment">// Send file size to the server</span>
conn.Write(fileSize)
</code></pre>
<h2 id="heading-reading-file-size-on-the-server-side">Reading File Size on the Server Side</h2>
<p>On the server side, we need to read the file size from the incoming data to allocate the necessary resources.</p>
<pre><code class="lang-go"><span class="hljs-comment">// Reading File Size on Server Side</span>

<span class="hljs-comment">// Create a buffer for receiving file size</span>
fileSizeBuffer := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">byte</span>, <span class="hljs-number">8</span>)

<span class="hljs-comment">// Read file size from the client</span>
_, err := conn.Read(fileSizeBuffer)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
    log.Fatal(err)
}

<span class="hljs-comment">// Convert bytes to uint64</span>
fileSize := binary.BigEndian.Uint64(fileSizeBuffer)
</code></pre>
<h2 id="heading-bringing-it-all-together">Bringing It All Together</h2>
<p>To complete the process, we can now integrate the techniques discussed to stream a large file. This involves sending the file size and subsequently streaming the data in manageable chunks.</p>
<pre><code class="lang-go"><span class="hljs-comment">// Streaming a Large File</span>

<span class="hljs-comment">// ... (Previous code for setting up connection and handling file)</span>

<span class="hljs-comment">// Send file size to the server</span>
conn.Write(fileSize)

<span class="hljs-comment">// Read and stream file data</span>
<span class="hljs-keyword">for</span> {
    bytesRead, err := file.Read(buffer)
    <span class="hljs-keyword">if</span> err == io.EOF {
        <span class="hljs-keyword">break</span>
    }
    conn.Write(buffer[:bytesRead])
}
</code></pre>
<p>Sequence diagram</p>
<pre><code class="lang-mermaid">sequenceDiagram
    participant Client
    participant Server
    Client-&gt;&gt;Server: Initiate TCP connection
    Server-&gt;&gt;Client: Accept TCP connection
    loop Until file is fully transferred
        Client-&gt;&gt;Client: Read file chunk
        Client-&gt;&gt;Server: Send chunk header (size, sequence number, etc.)
        Server-&gt;&gt;Client: Acknowledge chunk header
        Client-&gt;&gt;Server: Send chunk data
        Server-&gt;&gt;Client: Acknowledge chunk data
        Server-&gt;&gt;Server: Write chunk to file
    end
    Client-&gt;&gt;Server: Send file transfer completion signal
    Server-&gt;&gt;Client: Acknowledge completion
    Server-&gt;&gt;Client: Close TCP connection
    Client-&gt;&gt;Server: Close TCP connection
</code></pre>
<ol>
<li>Initiate TCP connection: The client starts the process by establishing a TCP connection with the server.</li>
<li>Accept TCP connection: The server accepts the incoming connection request from the client.</li>
<li>Read file chunk: The client reads a portion of the file into a buffer (chunk).</li>
<li>Send chunk header: The client sends information about the chunk (size, sequence number, etc.) to the server.</li>
<li>Acknowledge chunk header: The server confirms receipt of the chunk header.</li>
<li>Send chunk data: The client sends the actual chunk data to the server.</li>
<li>Acknowledge chunk data: The server confirms receipt of the chunk data.</li>
<li>Write chunk to file: The server writes the received chunk to the destination file.</li>
<li>Loop until completion: Steps 3-8 repeat until the entire file has been transferred.</li>
<li>Send completion signal: The client sends a signal to the server indicating that the file transfer is complete.</li>
<li>Acknowledge completion: The server acknowledges the completion signal.</li>
<li>Close TCP connection: Both the client and server close the TCP connection.</li>
</ol>
<h3 id="heading-key-points">Key Points:</h3>
<ul>
<li>Chunking: The file is divided into smaller chunks for efficient transmission and potential retransmission if errors occur.</li>
<li>Headers: Chunk headers contain metadata about the chunk, such as its size and sequence number, for proper reassembly at the server.</li>
<li>Acknowledgments: Server acknowledgments ensure reliable transfer and allow for retransmission if necessary.</li>
<li>Completion signal: The completion signal marks the end of the file transfer process.</li>
<li>TCP connection management: The TCP connection is established, maintained, and closed to ensure reliable data transfer.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we explored the challenges associated with handling large files in Golang and demonstrated how to implement a file server capable of streaming files over TCP connections. Leveraging the <code>net</code> and <code>io</code> packages, along with effective buffer usage, ensures efficient and reliable large file transfers. By including the file size as part of the data, we address the issue of not knowing the file size in advance, enabling seamless and secure streaming.</p>
]]></description><link>https://thediligentengineer.com/streaming-large-files-over-tcp</link><guid isPermaLink="true">https://thediligentengineer.com/streaming-large-files-over-tcp</guid><category><![CDATA[golang]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[streaming]]></category><dc:creator><![CDATA[The Diligent Engineer]]></dc:creator></item></channel></rss>