<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://ashwingopalsamy.in/feeds.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Ashwin Gopalsamy Library</title>
    <link>https://ashwingopalsamy.in/library/</link>
    <atom:link href="https://ashwingopalsamy.in/library/feed.xml" rel="self" type="application/rss+xml"/>
    <description>Books, watching, notes, and links</description>
    <language>en</language>
    <lastBuildDate>Tue, 07 Apr 2026 00:00:00 GMT</lastBuildDate>
    <ttl>60</ttl>
    <item>
      <title>Designing Rate Limiters for Payment Systems</title>
      <link>https://ashwingopalsamy.in/library/notes/designing-rate-limiters-for-payment-systems/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/designing-rate-limiters-for-payment-systems/</guid>
      <pubDate>Tue, 07 Apr 2026 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>Why payment rate limits can&apos;t treat false rejects like a normal API, and how to design for authorization ingress.</description>
      <content:encoded><![CDATA[<p>Rate limiting in payment systems is different from rate limiting in a typical web API. A false positive – rejecting a legitimate authorization – is a failed transaction. A customer’s card gets declined at checkout. That is not an acceptable failure mode.</p>
<h2 id="the-architecture">The Architecture<a class="h-anchor" href="#the-architecture" aria-hidden="true" tabindex="-1"></a></h2>
<p>A payment authorization pipeline typically looks like this:</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    A[Card Network] --&gt;|ISO 8583| B[Parser API]
    B --&gt;|gRPC| C[Distributor API]
    C --&gt;|gRPC| D[Account Service]
    C --&gt;|gRPC| E[Risk Engine]
    C --&gt;|gRPC| F[Ledger]</pre></figure>
<p>The rate limiter sits between the Parser API and the Distributor API. It must make a decision in under 1ms.</p>
<blockquote class="callout callout-warning" role="note" aria-label="Warning" data-callout="warning"><p class="callout-head"><span class="callout-icon"><svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.46 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg></span><span class="callout-label">Warning</span></p>
<p>Never rate-limit at the card network ingress point. Network protocols like ISO 8583 have strict timeout windows. A delayed response is worse than a fast decline: it triggers a reversal cascade.</p>
</blockquote>
<h2 id="choosing-an-algorithm">Choosing an Algorithm<a class="h-anchor" href="#choosing-an-algorithm" aria-hidden="true" tabindex="-1"></a></h2>
<h3 id="token-bucket">Token Bucket<a class="h-anchor" href="#token-bucket" aria-hidden="true" tabindex="-1"></a></h3>
<p>The token bucket algorithm maintains a counter that refills at a fixed rate. Each request consumes one token.</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>tokens</mtext><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>=</mo><mi>min</mi><mo>⁡</mo><mrow><mo fence="true">(</mo><mi>C</mi><mo separator="true">,</mo><mtext> tokens</mtext><mo stretchy="false">(</mo><msub><mi>t</mi><mn>0</mn></msub><mo stretchy="false">)</mo><mo>+</mo><mi>r</mi><mo>⋅</mo><mo stretchy="false">(</mo><mi>t</mi><mo>−</mo><msub><mi>t</mi><mn>0</mn></msub><mo stretchy="false">)</mo><mo fence="true">)</mo></mrow></mrow><annotation encoding="application/x-tex">\text{tokens}(t) = \min\left(C,\ \text{tokens}(t_0) + r \cdot (t - t_0)\right)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="katex-base"><span class="katex-strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord text"><span class="mord">tokens</span></span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="katex-base"><span class="katex-strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop">min</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;">(</span><span class="mord mathnormal" style="margin-right:0.0715em;">C</span><span class="mpunct">,</span><span class="mspace"> </span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord text"><span class="mord">tokens</span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="katex-sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord mathnormal" style="margin-right:0.0278em;">r</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="katex-sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mclose delimcenter" style="top:0em;">)</span></span></span></span></span></span></div>
<blockquote class="callout callout-tip" role="note" aria-label="Tip" data-callout="tip"><p class="callout-head"><span class="callout-icon"><svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8a6 6 0 0 0-12 0c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14"/></svg></span><span class="callout-label">Tip</span></p>
<p>Set C to handle your peak burst (Black Friday spike) and r to your sustained p99 throughput. For authorization systems, measure both per-issuer and per-BIN to avoid penalizing an entire bank for one merchant’s spike.</p>
</blockquote>
<h3 id="sliding-window-log">Sliding Window Log<a class="h-anchor" href="#sliding-window-log" aria-hidden="true" tabindex="-1"></a></h3>
<p>Tracks the exact timestamp of every request in a time window. Precise, but memory-intensive.</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>rate</mtext><mo>=</mo><mfrac><mi>n</mi><mi>W</mi></mfrac></mrow><annotation encoding="application/x-tex">\text{rate} = \frac{n}{W}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="katex-base"><span class="katex-strut" style="height:0.6151em;"></span><span class="mord text"><span class="mord">rate</span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="katex-base"><span class="katex-strut" style="height:1.7936em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.1076em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em;">W</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></div>
<h3 id="sliding-window-counter">Sliding Window Counter<a class="h-anchor" href="#sliding-window-counter" aria-hidden="true" tabindex="-1"></a></h3>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>count</mtext><mo>=</mo><mtext>prev</mtext><mo>×</mo><mrow><mo fence="true">(</mo><mn>1</mn><mo>−</mo><mfrac><msub><mi>t</mi><mtext>elapsed</mtext></msub><mi>W</mi></mfrac><mo fence="true">)</mo></mrow><mo>+</mo><mtext>curr</mtext></mrow><annotation encoding="application/x-tex">\text{count} = \text{prev} \times \left(1 - \frac{t_{\text{elapsed}}}{W}\right) + \text{curr}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="katex-base"><span class="katex-strut" style="height:0.6151em;"></span><span class="mord text"><span class="mord">count</span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="katex-base"><span class="katex-strut" style="height:0.7778em;vertical-align:-0.1944em;"></span><span class="mord text"><span class="mord">prev</span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="katex-base"><span class="katex-strut" style="height:2.4em;vertical-align:-0.95em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.2921em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.1389em;">W</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="katex-sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">elapsed</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="katex-base"><span class="katex-strut" style="height:0.4306em;"></span><span class="mord text"><span class="mord">curr</span></span></span></span></span></span></div>
<p><strong>Token Bucket:</strong> O(1) memory, O(1) time, allows bursts. No per-client fairness without separate buckets. Best for global throughput protection.</p>
<p><strong>Sliding Window:</strong> Precise rate tracking, smooth distribution. O(n) memory for log variant, interpolation error for counter variant. Best for per-client or per-issuer fairness.</p>
<h2 id="the-distributed-coordination-problem">The Distributed Coordination Problem<a class="h-anchor" href="#the-distributed-coordination-problem" aria-hidden="true" tabindex="-1"></a></h2>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">sequenceDiagram
    participant Client
    participant Region A
    participant Region B
    participant Redis
    Client-&gt;&gt;Region A: Auth Request 1
    Client-&gt;&gt;Region B: Auth Request 2
    Region A-&gt;&gt;Redis: INCR counter
    Region B-&gt;&gt;Redis: INCR counter
    Redis--&gt;&gt;Region A: count=1 (allow)
    Redis--&gt;&gt;Region B: count=2 (allow)</pre></figure>
<blockquote>
<p>The fundamental tension: strong consistency (single Redis) adds a network hop to every authorization, while eventual consistency allows brief over-admission. For payment systems, brief over-admission is almost always preferable to adding latency.</p>
</blockquote>
<h2 id="implementation-in-go">Implementation in Go<a class="h-anchor" href="#implementation-in-go" aria-hidden="true" tabindex="-1"></a></h2>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">type</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657"> TokenBucket</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> struct</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    mu       </span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">sync</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">.</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">Mutex</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    tokens   </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">float64</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    capacity </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">float64</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    rate     </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">float64</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    lastTime </span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">time</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">.</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">Time</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> (</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">tb </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">*</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">TokenBucket</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) </span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Allow</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">() </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">bool</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    tb.mu.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Lock</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">()</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    defer</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> tb.mu.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Unlock</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">()</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    now </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> time.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Now</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">()</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    elapsed </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> now.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Sub</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(tb.lastTime).</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Seconds</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">()</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    tb.tokens </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Min</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(tb.capacity, tb.tokens</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">+</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">tb.rate</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">*</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">elapsed)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    tb.lastTime </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> now</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> tb.tokens </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">&gt;=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 1</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        tb.tokens</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">--</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">        return</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> true</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    return</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> false</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<blockquote>
<p>This implementation uses a mutex for simplicity. In production, consider <code>sync/atomic</code> with CAS operations for lock-free performance, or a sharded bucket per goroutine with periodic merging.</p>
</blockquote>
<h2 id="key-takeaways">Key Takeaways<a class="h-anchor" href="#key-takeaways" aria-hidden="true" tabindex="-1"></a></h2>
<blockquote>
<p><strong>Design decisions for payment rate limiters:</strong></p>
<ul>
<li>Token bucket for global protection, sliding window for per-client fairness</li>
<li>Local-first with async sync beats centralized coordination for latency</li>
<li>Set capacity from measured burst patterns, not theoretical maximums</li>
<li>Monitor rejection rate as a business metric, not just an infra metric</li>
</ul>
</blockquote>
<p><strong>Web API Rate Limiting:</strong> Return 429 Too Many Requests. Client retries with backoff. False positives are annoying but recoverable.</p>
<p><strong>Payment Rate Limiting:</strong> Return decline response code in ISO 8583. No retry – transaction is failed. False positives are declined cards at checkout.</p>
<p>The difference between rate limiting a REST API and rate limiting an authorization pipeline is the cost of a false positive. In payments, you are not protecting a server – you are deciding whether someone’s groceries get paid for.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Understanding ISO 8583 Bitmap Parsing</title>
      <link>https://ashwingopalsamy.in/library/notes/understanding-iso8583-bitmaps/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/understanding-iso8583-bitmaps/</guid>
      <pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>How ISO 8583 bitmaps declare which data elements are present, and how to parse them at authorization ingress.</description>
      <content:encoded><![CDATA[<p>Every ISO 8583 message begins with a Message Type Indicator (MTI), followed by one or two bitmaps that declare which data elements are present in the message.</p>
<h2 id="what-is-a-bitmap">What is a Bitmap?<a class="h-anchor" href="#what-is-a-bitmap" aria-hidden="true" tabindex="-1"></a></h2>
<p>A bitmap is a binary structure where each bit position corresponds to a data element. If bit N is set to 1, data element N is present in the message. If it is 0, the element is absent.</p>
<p>The primary bitmap is always 64 bits (8 bytes). If bit 1 of the primary bitmap is set, a secondary bitmap follows, extending the field range from 65 to 128.</p>
<h2 id="parsing-in-go">Parsing in Go<a class="h-anchor" href="#parsing-in-go" aria-hidden="true" tabindex="-1"></a></h2>
<p>The parsing logic is straightforward once you understand the bit layout:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> ParseBitmap</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">data</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> []</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">byte</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) (</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">Bitmap</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">error</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    if</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> len</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(data) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">&lt;</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 8</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">        return</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657"> Bitmap</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">{}, fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Errorf</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"bitmap data too short: </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">%d</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> bytes"</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, </span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">len</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(data))</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    primary </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> binary.BigEndian.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Uint64</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(data[:</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">8</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">])</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    bm </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657"> Bitmap</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">{Primary: primary}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> primary</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">&amp;</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">1</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">&lt;&lt;</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">63</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">!=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 0</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">        if</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> len</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(data) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">&lt;</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 16</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">            return</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657"> Bitmap</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">{}, fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Errorf</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"secondary bitmap indicated but data too short"</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        }</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        bm.Secondary </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> binary.BigEndian.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Uint64</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(data[</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">8</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">:</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">16</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">])</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        bm.HasSecondary </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> true</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    return</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> bm, </span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">nil</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<h2 id="why-this-matters">Why This Matters<a class="h-anchor" href="#why-this-matters" aria-hidden="true" tabindex="-1"></a></h2>
<p>The elegance of this design is that the message is self-describing. No schema negotiation, no version headers, no content-type declarations. The bitmap IS the schema.</p>
<p>This means a parser can handle any valid ISO 8583 message without knowing in advance which fields will be present. The bitmap tells it exactly what to expect and where to find it.</p>
<h2 id="key-takeaways">Key Takeaways<a class="h-anchor" href="#key-takeaways" aria-hidden="true" tabindex="-1"></a></h2>
<ul>
<li>Primary bitmap: bits 1-64, always present (8 bytes)</li>
<li>Secondary bitmap: bits 65-128, present only if bit 1 of primary is set</li>
<li>Each bit maps to one data element by position</li>
<li>Bit numbering starts at 1, not 0 (bit 1 is the MSB of the first byte)</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Go Error Wrapping Patterns</title>
      <link>https://ashwingopalsamy.in/library/notes/go-error-wrapping/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/go-error-wrapping/</guid>
      <pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>The fmt.Errorf %w pattern and the nuances of wrapping, unwrapping, and adding context to Go errors.</description>
      <content:encoded><![CDATA[<p>The <code>fmt.Errorf("context: %w", err)</code> pattern is the standard way to add context to errors in Go. But there are nuances worth knowing.</p>
<p>Always wrap with context that answers “what were you trying to do?” not “what went wrong?” The original error already says what went wrong.</p>
<p>Bad: <code>fmt.Errorf("error: %w", err)</code>
Good: <code>fmt.Errorf("parsing field DE%d: %w", fieldNum, err)</code></p>
]]></content:encoded>
    </item>
    <item>
      <title>Anatomy of a Supply Chain Attack: LiteLLM on PyPI</title>
      <link>https://ashwingopalsamy.in/library/notes/litellm-supply-chain-attack/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/litellm-supply-chain-attack/</guid>
      <pubDate>Wed, 25 Mar 2026 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>How a compromised LiteLLM package on PyPI reached a Cursor MCP plugin: anatomy of a real supply-chain hit.</description>
      <content:encoded><![CDATA[<p>On March 24, 2026, Callum McMahon at FutureSearch was testing a Cursor MCP plugin that pulled in litellm as a transitive dependency. Shortly after, his machine became unresponsive. He traced it to a newly installed litellm package.</p>
<h2 id="what-is-litellm">What Is LiteLLM?<a class="h-anchor" href="#what-is-litellm" aria-hidden="true" tabindex="-1"></a></h2>
<p>LiteLLM is a Python library that works like a universal remote for AI APIs. 95 million downloads per month on PyPI. ~40,000 GitHub stars.</p>
<h2 id="the-attack-chain">The Attack Chain<a class="h-anchor" href="#the-attack-chain" aria-hidden="true" tabindex="-1"></a></h2>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">sequenceDiagram
    participant A as Attacker (TeamPCP)
    participant T as Trivy GitHub Repo
    participant CI as LiteLLM CI (GitHub Actions)
    participant P as PyPI Registry
<!--diagram-blank-->
    Note over A,T: March 1 - Initial Compromise
    A-&gt;&gt;T: Submit malicious PR (Pwn Request)
    T--&gt;&gt;A: CI leaks personal access token
    Note over CI,P: March 24 - Package Takeover
    CI-&gt;&gt;T: Pull trivy-action@latest (not pinned to SHA)
    T--&gt;&gt;CI: Serve compromised action
    CI--&gt;&gt;A: Leak PyPI publisher token
    A-&gt;&gt;P: Publish litellm v1.82.7 (inline payload)
    A-&gt;&gt;P: Publish litellm v1.82.8 (.pth persistence)</pre></figure>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    A["Trivy Repo\n(compromised)"] --&gt; B["GitHub Bot Army"]
    B --&gt; C["PyPI Account Takeover"]
    C --&gt; D["LiteLLM v1.82.7 / v1.82.8"]
    D --&gt; E[".pth Backdoor"]
    E --&gt; F["Credential Harvest"]
    F --&gt; G["Exfil Server (ICP Canister)"]</pre></figure>
<h2 id="what-the-malware-does">What the Malware Does<a class="h-anchor" href="#what-the-malware-does" aria-hidden="true" tabindex="-1"></a></h2>
<p>The payload was triple-nested: a base64 blob decodes to an orchestrator script, which decodes a second base64 blob containing the harvester.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph TD
    ROOT[".pth Backdoor"]
    ROOT --&gt; ENV["ENV Variables"]
    ROOT --&gt; AWS["~/.aws/credentials"]
    ROOT --&gt; DOTENV[".env Files"]
    ROOT --&gt; PROC["/proc/self/environ"]
    ROOT --&gt; EXFIL["Outbound HTTP Exfil to ICP canister"]
    ENV --&gt; EXFIL
    AWS --&gt; EXFIL
    DOTENV --&gt; EXFIL
    PROC --&gt; EXFIL</pre></figure>
<p>Two versions were published:</p>
<ul>
<li>v1.82.7: injected payload at line 128 of <code>litellm/proxy/proxy_server.py</code></li>
<li>v1.82.8: added a <code>.pth</code> file that executes every time Python starts</li>
</ul>
<blockquote>
<p><code>.pth</code> files in <code>site-packages</code> execute code before your application begins, on every Python invocation: pytest, IDE language server, even pip install.</p>
</blockquote>
<h2 id="check-your-environment">Check Your Environment<a class="h-anchor" href="#check-your-environment" aria-hidden="true" tabindex="-1"></a></h2>
<div class="code-figure" data-language="bash"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="--shiki-light:#953800;--shiki-dark:#FFA657">ls</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> ~/.config/sysmon/sysmon.py</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> 2&gt;</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">/dev/null</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> &amp;&amp; </span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">echo</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> "BACKDOOR FOUND"</span></span>
<span class="line"><span style="--shiki-light:#953800;--shiki-dark:#FFA657">find</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> $(</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">python3</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> -c</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> "import site; print(' '.join(site.getsitepackages()))"</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">\</span></span>
<span class="line"><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">  -name</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> "litellm_init.pth"</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> 2&gt;</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">/dev/null</span></span></code></pre></div>
<blockquote>
<p>If anything shows up, upgrading the package is not enough. Rotate all LLM provider API keys, cloud credentials, GitHub and PyPI tokens, CI/CD secrets, and SSH keys. Rebuild from known-good images. The last known-clean version is 1.82.6.</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>Consistent Hashing in Distributed Caches</title>
      <link>https://ashwingopalsamy.in/library/notes/consistent-hashing-distributed-caches/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/consistent-hashing-distributed-caches/</guid>
      <pubDate>Sun, 15 Mar 2026 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>How consistent hashing keeps cache keys stable when nodes join or leave, and why modular hashing fails under churn.</description>
      <content:encoded><![CDATA[<p>When you distribute data across multiple cache nodes, the naive approach is modular hashing: <code>node = hash(key) % num_nodes</code>. This works until you add or remove a node.</p>
<h2 id="the-problem-with-modular-hashing">The Problem with Modular Hashing<a class="h-anchor" href="#the-problem-with-modular-hashing" aria-hidden="true" tabindex="-1"></a></h2>
<p>If you have 4 nodes and add a 5th, almost every key remaps to a different node. With <code>hash(key) % 4</code> becoming <code>hash(key) % 5</code>, roughly 80% of your cache is invalidated instantly. Under load, this is a cache stampede.</p>
<h2 id="how-consistent-hashing-works">How Consistent Hashing Works<a class="h-anchor" href="#how-consistent-hashing-works" aria-hidden="true" tabindex="-1"></a></h2>
<p>Consistent hashing arranges the hash space into a ring. Each node is assigned one or more positions on the ring. A key is hashed to a position, and the first node clockwise from that position owns the key.</p>
<p>When a node joins, it takes responsibility for a portion of its neighbor’s range. When a node leaves, its range is absorbed by the next node clockwise. In both cases, only <code>K/N</code> keys need to move, where K is the total number of keys and N is the number of nodes.</p>
<h2 id="virtual-nodes">Virtual Nodes<a class="h-anchor" href="#virtual-nodes" aria-hidden="true" tabindex="-1"></a></h2>
<p>Real implementations use virtual nodes – each physical node gets multiple positions on the ring. This smooths out the distribution and prevents hotspots caused by uneven hash space allocation.</p>
<h2 id="key-takeaways">Key Takeaways<a class="h-anchor" href="#key-takeaways" aria-hidden="true" tabindex="-1"></a></h2>
<ul>
<li>Modular hashing invalidates ~(N-1)/N keys on node changes</li>
<li>Consistent hashing invalidates only ~K/N keys</li>
<li>Virtual nodes solve the distribution imbalance problem</li>
<li>Used by DynamoDB, Cassandra, Memcached, and most distributed caches</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Why slog Over zerolog</title>
      <link>https://ashwingopalsamy.in/library/notes/slog-structured-logging/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/slog-structured-logging/</guid>
      <pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>Why slog is my default over zerolog for new Go projects after log/slog landed in the standard library.</description>
      <content:encoded><![CDATA[<p>Go 1.21 introduced <code>log/slog</code> in the standard library. For new projects, I now default to slog over zerolog.</p>
<p>The API is cleaner, it is part of the standard library (no dependency), and the handler interface makes it trivial to swap backends. The performance gap that once justified zerolog has narrowed significantly.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Why UUIDs Matter for Idempotency</title>
      <link>https://ashwingopalsamy.in/library/notes/uuids-for-idempotency/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/uuids-for-idempotency/</guid>
      <pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>Why idempotency keys matter in payments: processing the same authorization twice is worse than rejecting it.</description>
      <content:encoded><![CDATA[<p>In payment processing, processing the same authorization twice is worse than rejecting it. A customer charged twice loses trust immediately. Idempotency keys prevent this.</p>
<h2 id="the-problem">The Problem<a class="h-anchor" href="#the-problem" aria-hidden="true" tabindex="-1"></a></h2>
<p>A client sends an authorization request. The network drops the response. The client retries. Without idempotency, the server processes the authorization again, resulting in a double charge.</p>
<h2 id="uuids-as-idempotency-keys">UUIDs as Idempotency Keys<a class="h-anchor" href="#uuids-as-idempotency-keys" aria-hidden="true" tabindex="-1"></a></h2>
<p>The client generates a UUID before the first attempt and includes it in every retry. The server checks: have I seen this UUID before? If yes, return the original response. If no, process the request and store the UUID with its response.</p>
<h2 id="why-uuid-v7">Why UUID v7<a class="h-anchor" href="#why-uuid-v7" aria-hidden="true" tabindex="-1"></a></h2>
<p>UUID v7 embeds a Unix timestamp in the first 48 bits, followed by random bits. This gives you:</p>
<ul>
<li><strong>Chronological ordering</strong>: UUIDs sort by creation time, which makes database indexes efficient</li>
<li><strong>Uniqueness</strong>: the random component prevents collisions even at high throughput</li>
<li><strong>Expiry</strong>: you can garbage-collect old idempotency records by inspecting the embedded timestamp</li>
</ul>
<h2 id="key-takeaways">Key Takeaways<a class="h-anchor" href="#key-takeaways" aria-hidden="true" tabindex="-1"></a></h2>
<ul>
<li>Idempotency keys prevent duplicate processing in distributed systems</li>
<li>UUID v7 provides time-ordered uniqueness without coordination</li>
<li>The embedded timestamp enables efficient cleanup of expired records</li>
<li>Always generate the idempotency key client-side, never server-side</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Cloud Native Go</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2026-01-05:books/cloud-native-go</guid>
      <pubDate>Mon, 05 Jan 2026 00:00:00 GMT</pubDate>
      <category>books</category>
    </item>
    <item>
      <title>Alex Edwards - Let&apos;s Go</title>
      <link>https://www.alexedwards.net/blog</link>
      <guid isPermaLink="false">https://www.alexedwards.net/blog</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>alexedwards.net</description>
    </item>
    <item>
      <title>Anton Zaides - All Articles</title>
      <link>https://antonz.org/all/</link>
      <guid isPermaLink="false">https://antonz.org/all/</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>antonz.org</description>
    </item>
    <item>
      <title>Building Large Technical Projects</title>
      <link>https://mitchellh.com/writing/building-large-technical-projects</link>
      <guid isPermaLink="false">https://mitchellh.com/writing/building-large-technical-projects</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>mitchellh.com</description>
    </item>
    <item>
      <title>Cloudflare Blog</title>
      <link>https://blog.cloudflare.com/</link>
      <guid isPermaLink="false">https://blog.cloudflare.com/</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>blog.cloudflare.com</description>
    </item>
    <item>
      <title>Dave Cheney&apos;s Blog</title>
      <link>https://dave.cheney.net/</link>
      <guid isPermaLink="false">https://dave.cheney.net/</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>dave.cheney.net</description>
    </item>
    <item>
      <title>Effective Go</title>
      <link>https://go.dev/doc/effective_go</link>
      <guid isPermaLink="false">https://go.dev/doc/effective_go</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>go.dev</description>
    </item>
    <item>
      <title>How I Solved the 1BRC in Go</title>
      <link>https://benhoyt.com/writings/go-1brc/</link>
      <guid isPermaLink="false">https://benhoyt.com/writings/go-1brc/</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>benhoyt.com</description>
    </item>
    <item>
      <title>Visualizing Go Concurrency</title>
      <link>https://divan.dev/posts/go_concurrency_visualize/</link>
      <guid isPermaLink="false">https://divan.dev/posts/go_concurrency_visualize/</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>divan.dev</description>
    </item>
    <item>
      <title>Go for Industrial Programming</title>
      <link>https://peter.bourgon.org/go-for-industrial-programming/</link>
      <guid isPermaLink="false">https://peter.bourgon.org/go-for-industrial-programming/</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>peter.bourgon.org</description>
    </item>
    <item>
      <title>How I Write HTTP Services in Go After 13 Years</title>
      <link>https://grafana.com/blog/how-i-write-http-services-in-go-after-13-years/</link>
      <guid isPermaLink="false">https://grafana.com/blog/how-i-write-http-services-in-go-after-13-years/</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>grafana.com</description>
    </item>
    <item>
      <title>The Pragmatic Engineer</title>
      <link>https://blog.pragmaticengineer.com/</link>
      <guid isPermaLink="false">https://blog.pragmaticengineer.com/</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>blog.pragmaticengineer.com</description>
    </item>
    <item>
      <title>Uber Engineering Blog</title>
      <link>https://www.uber.com/in/en/blog/engineering/</link>
      <guid isPermaLink="false">https://www.uber.com/in/en/blog/engineering/</guid>
      <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
      <category>articles</category>
      <description>uber.com</description>
    </item>
    <item>
      <title>Go Maps Iteration Order</title>
      <link>https://ashwingopalsamy.in/library/notes/go-maps-iteration-order/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/go-maps-iteration-order/</guid>
      <pubDate>Thu, 25 Dec 2025 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>Go map iteration is intentionally random; why sorted-looking output is a trap, not a guarantee.</description>
      <content:encoded><![CDATA[<p>I was working on a minimal word counter. Read from stdin, normalize the input, increment the value for the keys in a <code>map[string]int</code>. The output looked sorted. Alphabetically sorted.</p>
<p>I ran it again. Same order. Added more input. Still sorted.</p>
<p>At that point, my instincts kicked in. Go maps are unordered. I knew that. So why was the output behaving so politely?</p>
<h2 id="the-non-negotiable-fact">The non-negotiable fact<a class="h-anchor" href="#the-non-negotiable-fact" aria-hidden="true" tabindex="-1"></a></h2>
<p>Go maps do not guarantee iteration order. Ever. The language spec is explicit.</p>
<h2 id="what-is-actually-happening-inside-a-go-map">What is actually happening inside a Go map<a class="h-anchor" href="#what-is-actually-happening-inside-a-go-map" aria-hidden="true" tabindex="-1"></a></h2>
<p>A Go map is a hash table. Iteration walks buckets in a runtime-defined sequence, not key order.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    subgraph "Hash Function"
        H["hash(key)"]
    end
    K1["a"] --&gt; H
    K2["b"] --&gt; H
    K3["m"] --&gt; H
    K4["1"] --&gt; H
    H --&gt; B0["Bucket 0\n1"]
    H --&gt; B1["Bucket 1\n2"]
    H --&gt; B3["Bucket 3\na"]
    H --&gt; B4["Bucket 4\nb"]
    H --&gt; B6["Bucket 6\nm"]</pre></figure>
<h2 id="why-the-output-looked-sorted">Why the output looked sorted<a class="h-anchor" href="#why-the-output-looked-sorted" aria-hidden="true" tabindex="-1"></a></h2>
<p>Small number of keys, short ASCII strings, no map resizing during insertion. Under these conditions, hash values distribute nicely across buckets, and the bucket layout in memory often correlates with lexical order. By coincidence.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph TD
    S["Small ASCII key set"]
    L["Large / diverse key set"]
    S --&gt; O1["Appears sorted (coincidence)"]
    L --&gt; O2["Visibly unordered (reality)"]</pre></figure>
<h2 id="a-simplified-mental-model">A simplified mental model<a class="h-anchor" href="#a-simplified-mental-model" aria-hidden="true" tabindex="-1"></a></h2>
<div class="code-figure" data-language="plaintext"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>Input keys:  a   b   m   x   y   z   1   2   9</span></span>
<span class="line"><span></span></span>
<span class="line"><span>Buckets in memory order:</span></span>
<span class="line"><span>[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]</span></span>
<span class="line"><span> 1   2   9   a   b       m           x    y    z</span></span>
<span class="line"><span></span></span>
<span class="line"><span>Iteration walks buckets left to right:</span></span>
<span class="line"><span>1 2 9 a b m x y z</span></span></code></pre></div>
<p>Digits first. Then letters. Within each group, alphabetical-looking. No sorting happened. Change the input distribution, force collisions, trigger a map resize, and this illusion breaks instantly.</p>
<blockquote>
<p>Deterministic-looking behavior does not imply guarantees.</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>Database Internals</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2025-11-20:books/database-internals</guid>
      <pubDate>Thu, 20 Nov 2025 00:00:00 GMT</pubDate>
      <category>books</category>
    </item>
    <item>
      <title>Floating-Point Tolerance Testing in Go</title>
      <link>https://ashwingopalsamy.in/library/notes/go-floating-point-tolerance-testing/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/go-floating-point-tolerance-testing/</guid>
      <pubDate>Sun, 17 Aug 2025 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>Why 0.1 + 0.2 isn&apos;t 0.3 in financial Go tests, and how to assert floating-point results with tolerance.</description>
      <content:encoded><![CDATA[<p>Last Tuesday, I was knee-deep in a financial calculation service when my tests started failing. You know that sinking feeling when <code>0.1 + 0.2</code> doesn’t equal <code>0.3</code>? That was my afternoon.</p>
<p>This got me thinking about when we actually need tolerance-based comparisons versus when we’re just cargo-culting best practices.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    A["0.1 + 0.2"] --&gt; B["IEEE 754"]
    B --&gt; C["0.30000...04"]
    D["0.3"] --&gt; E["IEEE 754"]
    E --&gt; F["0.29999...99"]
    C --&gt; G["Gap = epsilon"]
    F --&gt; G</pre></figure>
<h2 id="when-tolerance-matters">When tolerance matters<a class="h-anchor" href="#when-tolerance-matters" aria-hidden="true" tabindex="-1"></a></h2>
<p>I was working on a discount calculation system:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> calculateDiscount</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">price</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, </span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">rate</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> float64</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">float64</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    return</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> price </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">*</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> rate</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> TestDiscountCalculation</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">t</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> *</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">testing</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">.</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    price </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 29.99</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    rate </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 0.15</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    expected </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 4.4985</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    result </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> calculateDiscount</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(price, rate)</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> result </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">!=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> expected {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        t.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Errorf</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"got </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">%v</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">, want </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">%v</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, result, expected)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<p>With tolerance, you’d handle it like this:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> almostEqual</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">a</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, </span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">b</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, </span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">tolerance</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> float64</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">bool</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    return</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Abs</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(a</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">-</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">b) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">&lt;=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> tolerance</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> TestDiscountCalculationWithTolerance</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">t</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> *</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">testing</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">.</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    price </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 29.99</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    rate </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 0.15</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    expected </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 4.4985</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    result </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> calculateDiscount</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(price, rate)</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    if</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> !</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">almostEqual</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(result, expected, </span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">1</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">e-</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">9</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        t.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Errorf</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"got </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">%v</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">, want </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">%v</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, result, expected)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<h2 id="when-you-dont-need-tolerance">When you DON’T need tolerance<a class="h-anchor" href="#when-you-dont-need-tolerance" aria-hidden="true" tabindex="-1"></a></h2>
<p>Some comparisons are fine without tolerance:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> value </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">==</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 0.0</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> { } </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// Zero has exact representation</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">IsNaN</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(result) { } </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// Special values</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> result </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">==</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Inf</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">1</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) { } </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// Infinity comparisons</span></span></code></pre></div>
<p>If your floats haven’t been through different computational paths, exact comparison often works fine.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">flowchart TD
    A["Comparing floats?"] --&gt; B{"Result of\narithmetic?"}
    B -- Yes --&gt; C["Use epsilon"]
    B -- No --&gt; D{"Integer-\nconvertible?"}
    D -- Yes --&gt; E["No epsilon needed"]
    D -- No --&gt; F{"Currency?"}
    F -- Yes --&gt; G["Use integer cents"]
    F -- No --&gt; C</pre></figure>
<h2 id="a-practical-helper">A practical helper<a class="h-anchor" href="#a-practical-helper" aria-hidden="true" tabindex="-1"></a></h2>
<p>Here’s a utility I use across projects:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> DefaultFloatTolerance</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 1</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">e-</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">9</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> FloatEquals</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">a</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, </span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">b</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> float64</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">bool</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    return</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> FloatEqualsWithTolerance</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(a, b, DefaultFloatTolerance)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> FloatEqualsWithTolerance</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">a</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, </span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">b</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, </span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">tolerance</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> float64</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">bool</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">IsNaN</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(a) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">&amp;&amp;</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">IsNaN</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(b) {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">        return</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> true</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">IsInf</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(a, </span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">0</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">&amp;&amp;</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">IsInf</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(b, </span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">0</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">        return</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Signbit</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(a) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">==</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Signbit</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(b)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    return</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Abs</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(a</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">-</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">b) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">&lt;=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> tolerance</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<p>Use tolerance when your floats have been through computational journeys. Skip it for direct assignments, constants, and same-path calculations.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Designing Data-Intensive Applications</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2025-08-15:books/designing-data-intensive-applications</guid>
      <pubDate>Fri, 15 Aug 2025 00:00:00 GMT</pubDate>
      <category>books</category>
    </item>
    <item>
      <title>Runes, Bytes, and Graphemes in Go</title>
      <link>https://ashwingopalsamy.in/library/notes/runes-bytes-and-graphemes-in-go/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/runes-bytes-and-graphemes-in-go/</guid>
      <pubDate>Sat, 09 Aug 2025 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>Bytes, runes, and graphemes are not the same length: handling Tamil and emoji correctly in Go strings.</description>
      <content:encoded><![CDATA[<p>I once ran into this problem while handling names in Tamil and emoji in a Go web app: a string that looked short wasn’t, and reversing it produced gibberish.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph TD
    G["Grapheme Cluster\n(what users see)"]
    R1["Rune 1\n(code point)"]
    R2["Rune 2\n(combining mark)"]
    B1["Bytes\n(1-4 per rune)"]
    B2["Bytes\n(1-4 per rune)"]
    G --&gt; R1
    G --&gt; R2
    R1 --&gt; B1
    R2 --&gt; B2</pre></figure>
<h2 id="1-bytes">1. Bytes<a class="h-anchor" href="#1-bytes" aria-hidden="true" tabindex="-1"></a></h2>
<p>Go represents strings as immutable UTF-8 byte sequences.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">s </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> "வணக்கம்"</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Println</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">len</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(s)) </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// 21</span></span></code></pre></div>
<p>21 bytes, not visible symbols. Every Tamil character can span 3 bytes.</p>
<h2 id="2-runes">2. Runes<a class="h-anchor" href="#2-runes" aria-hidden="true" tabindex="-1"></a></h2>
<p><code>string</code> to <code>[]rune</code> gives you code points.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">rs </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> []</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">rune</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(s)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Println</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">len</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(rs)) </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// 7</span></span></code></pre></div>
<p>7 runes, but some Tamil graphemes (like “க்”) combine two runes: க + ்.</p>
<h2 id="3-grapheme-clusters">3. Grapheme clusters<a class="h-anchor" href="#3-grapheme-clusters" aria-hidden="true" tabindex="-1"></a></h2>
<p>Go’s standard library stops at runes. For visible character units, use <code>github.com/rivo/uniseg</code>.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">for</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> gr </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> uniseg.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">NewGraphemes</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(s); gr.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Next</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(); {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Printf</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">%q\n</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, gr.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Str</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">())</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<p>That outputs what a human reads: வ, ண, க், க, ம்.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    T["வணக்கம் (Tamil)"]
    T --&gt; |"len()"| BY["21 bytes"]
    T --&gt; |"[]rune"| RU["7 runes"]
    T --&gt; |"uniseg"| GR["5 graphemes"]</pre></figure>
<h2 id="quick-reference">Quick reference<a class="h-anchor" href="#quick-reference" aria-hidden="true" tabindex="-1"></a></h2>
<div class="table-scroll"><table>
<thead>
<tr>
<th>Task</th>
<th>Approach</th>
</tr>
</thead>
<tbody>
<tr>
<td>Count code points</td>
<td><code>utf8.RuneCountInString(s)</code></td>
</tr>
<tr>
<td>Count visible units</td>
<td>Grapheme iteration (uniseg)</td>
</tr>
<tr>
<td>Reverse text</td>
<td>Parse into graphemes, reverse slice, join</td>
</tr>
<tr>
<td>Slice safely</td>
<td>Only use <code>s[i:j]</code> on grapheme boundaries</td>
</tr>
</tbody>
</table></div>
]]></content:encoded>
    </item>
    <item>
      <title>Go Was Never Bad</title>
      <link>https://ashwingopalsamy.in/library/notes/go-was-never-bad/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/go-was-never-bad/</guid>
      <pubDate>Sat, 21 Jun 2025 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>Go is not for everything, and that was never the point. A defense of brutal minimalism for cloud systems.</description>
      <content:encoded><![CDATA[<p>Every time I see that GitHub repo go-is-not-good making the rounds again, I laugh. It’s always shared by people who mistake language cleverness for engineering.</p>
<p>Let me say this clearly: Go is not for everything. It was never meant to be. But if you’re building cloud-native systems, if you’re working with distributed architecture, if you’re running services in production that actually matter – Go is brutal, minimal, and effective.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    A["No generics"] -- "Go 1.18" --&gt; B["Resolved"]
    C["No modules"] -- "Go 1.11" --&gt; D["Resolved"]
    E["Error handling"] --&gt; F["By Design"]
    G["Concurrency"] --&gt; H["Same as every lang"]</pre></figure>
<h2 id="generics">Generics<a class="h-anchor" href="#generics" aria-hidden="true" tabindex="-1"></a></h2>
<p>Go 1.18 brought generics. Not the “look how clever I am” kind. The real-world, clean, no-BS kind. I’ve built production-grade code with generics in Go, and it’s boring in the best possible way.</p>
<h2 id="error-handling">Error Handling<a class="h-anchor" href="#error-handling" aria-hidden="true" tabindex="-1"></a></h2>
<p>I respect Go’s approach to error handling. It makes you look at your failure paths. There’s no magic trapdoor. You deal with errors explicitly, predictably, and with clarity. Now with <code>errors.Is</code>, <code>errors.As</code>, and <code>errors.Join</code>, it’s not even painful.</p>
<h2 id="go-does-not-babysit-your-concurrency">Go does not babysit your Concurrency<a class="h-anchor" href="#go-does-not-babysit-your-concurrency" aria-hidden="true" tabindex="-1"></a></h2>
<p>Go gives you the raw tools to build concurrent systems. It assumes the person writing the code knows what they’re doing. I respect that.</p>
<h2 id="performance">Performance<a class="h-anchor" href="#performance" aria-hidden="true" tabindex="-1"></a></h2>
<p>I’ve deployed Go services that boot in under 50ms and run for months without a hiccup. It doesn’t brag. It just works.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    A["Go"] --&gt; B["Ship fast, simple"]
    C["Java / Spring"] --&gt; D["Medium complexity"]
    E["Rust / Haskell"] --&gt; F["Complex, more guarantees"]</pre></figure>
<h2 id="personal-take">Personal take<a class="h-anchor" href="#personal-take" aria-hidden="true" tabindex="-1"></a></h2>
<p>I’ve built banking systems, transaction processors, and cloud-native APIs with Go. It’s not flashy. But Go keeps things simple and predictable, and that’s exactly what backend engineering demands.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Rookie</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2025-06-15:watch/rookie</guid>
      <pubDate>Sun, 15 Jun 2025 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>How Goroutine Stacks Grow and Shrink</title>
      <link>https://ashwingopalsamy.in/library/notes/go-goroutine-stack-growth/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/go-goroutine-stack-growth/</guid>
      <pubDate>Sun, 08 Jun 2025 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>How goroutine stacks grow and shrink in Go, and why that is what makes them feel lightweight.</description>
      <content:encoded><![CDATA[<p>If you ask any mid-senior Go dev what makes goroutines lightweight you’ll get the reply:</p>
<blockquote>
<p>They start with 2 KB of stack instead of 1 MB like OS threads.</p>
</blockquote>
<p>They’re not wrong. But they’re not thinking deep enough.</p>
<p>Go’s stack model isn’t just a small preallocated buffer; it’s a live, evolving region of memory that resizes in realtime, grows when needed, and shrinks.</p>
<p>Go’s runtime gives each new goroutine 2 KB of stack. But Go doesn’t panic when you blow past it – it grows the stack dynamically by allocating a new region (typically doubling the size) and copying the old stack frames over.</p>
<h3 id="stack-growth-lifecycle">Stack Growth Lifecycle<a class="h-anchor" href="#stack-growth-lifecycle" aria-hidden="true" tabindex="-1"></a></h3>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    A["New Goroutine\n2 KB stack"] --&gt; B["Function\nCall"]
    B --&gt; C{"Stack\nCheck"}
    C --&gt;|Enough| D["Continue\nExecution"]
    C --&gt;|Overflow| E["Allocate\n2x Stack"]
    E --&gt; F["Copy Old\nFrames"]
    F --&gt; G["Update\nPointers"]
    G --&gt; D</pre></figure>
<p>Each goroutine has an upper stack limit of about 1 GB. Hit it and the program panics:</p>
<div class="code-figure" data-language="plaintext"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>runtime: goroutine stack exceeds 1000000000-byte limit</span></span>
<span class="line"><span>fatal error: stack overflow</span></span></code></pre></div>
<h3 id="stack-size-progression">Stack Size Progression<a class="h-anchor" href="#stack-size-progression" aria-hidden="true" tabindex="-1"></a></h3>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph TD
    S1["2 KB\n(initial)"] --&gt; S2["4 KB"]
    S2 --&gt; S3["8 KB"]
    S3 --&gt; S4["16 KB"]
    S4 --&gt; S5["32 KB"]
    S5 --&gt; S6["..."]
    S6 --&gt; S7["~1 GB\n(ceiling)"]
    S7 -.-&gt;|"GC shrink\n(if idle + mostly unused)"| S5
    S5 -.-&gt;|"GC shrink"| S3</pre></figure>
<h3 id="contiguous-stack-copy">Contiguous Stack Copy<a class="h-anchor" href="#contiguous-stack-copy" aria-hidden="true" tabindex="-1"></a></h3>
<p>When a stack outgrows its current allocation, Go allocates a new contiguous block at double the size, copies all frames, and adjusts every internal pointer.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    subgraph "Old Stack (4 KB)"
        O1["Frame 1"]
        O2["Frame 2"]
        O3["Pointer A\n→ Frame 1"]
    end
    subgraph "New Stack (8 KB)"
        N1["Frame 1\n(copied)"]
        N2["Frame 2\n(copied)"]
        N3["Pointer A'\n→ Frame 1\n(adjusted)"]
        N4["Free Space"]
    end
    O1 --&gt;|copy| N1
    O2 --&gt;|copy| N2
    O3 --&gt;|"adjust + copy"| N3</pre></figure>
<blockquote>
<p>Stack growth can trigger GC pressure even without heap allocations. A runaway stack holds pointers that get scanned by GC. This is how your 5ms p99 turns into 100ms.</p>
</blockquote>
<p>There’s no tuning knob for stack size. No config. No CLI flag. The only way to manage it is through code discipline: avoid recursive goroutines unless they terminate quickly, don’t hold large structs deep in call graphs, and never assume goroutines are free.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Go Scheduler, Yield Points, and Infinite Loops</title>
      <link>https://ashwingopalsamy.in/library/notes/go-scheduler-infinite-loops/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/go-scheduler-infinite-loops/</guid>
      <pubDate>Sat, 24 May 2025 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>How Go&apos;s scheduler, yield points, and tight loops interact, and when a busy loop starves other goroutines.</description>
      <content:encoded><![CDATA[<p>I’ve been reviewing performance-critical code, and I keep coming back to this pattern:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">for</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> condition {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">        break</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<p>versus</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">go</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> func</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">() {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    for</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">        // background processing</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}()</span></span></code></pre></div>
<p>The runtime implications are fascinating.</p>
<h2 id="the-gmp-model">The GMP Model<a class="h-anchor" href="#the-gmp-model" aria-hidden="true" tabindex="-1"></a></h2>
<p>Go’s scheduler uses a GMP model: Goroutines (G) run on Machine threads (M) via Processors (P). Each P has a local run queue plus a global run queue.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph TD
    subgraph "Global Run Queue"
        GQ["G5, G6, G7 ..."]
    end
    subgraph "P0 (Processor)"
        LQ0["Local Queue:\nG1, G2"]
        LQ0 --&gt; M0["M0\n(OS Thread)"]
        M0 --&gt; CPU0["CPU Core 0"]
    end
    subgraph "P1 (Processor)"
        LQ1["Local Queue:\nG3, G4"]
        LQ1 --&gt; M1["M1\n(OS Thread)"]
        M1 --&gt; CPU1["CPU Core 1"]
    end
    GQ -.-&gt;|"schedule"| LQ0
    GQ -.-&gt;|"schedule"| LQ1
    LQ0 -.-&gt;|"work steal"| LQ1</pre></figure>
<h3 id="cooperative-scheduling">Cooperative Scheduling<a class="h-anchor" href="#cooperative-scheduling" aria-hidden="true" tabindex="-1"></a></h3>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">sequenceDiagram
    participant S as Scheduler
    participant A as Goroutine A
    participant B as Goroutine B
<!--diagram-blank-->
    S-&gt;&gt;A: Schedule on P0
    Note over A: Executing...
    A-&gt;&gt;A: Channel send (yield point)
    A-&gt;&gt;S: Yield control
    S-&gt;&gt;B: Schedule on P0
    Note over B: Executing...
    B-&gt;&gt;B: runtime.Gosched()
    B-&gt;&gt;S: Yield control
    S-&gt;&gt;A: Re-schedule on P0
    Note over A: Resumes execution</pre></figure>
<h3 id="async-preemption">Async Preemption<a class="h-anchor" href="#async-preemption" aria-hidden="true" tabindex="-1"></a></h3>
<p>Since Go 1.14, <code>sysmon</code> detects goroutines running longer than ~10ms and forces preemption via SIGURG.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">sequenceDiagram
    participant SM as sysmon
    participant G as Goroutine (tight loop)
    participant S as Scheduler
<!--diagram-blank-->
    G-&gt;&gt;G: Running for &gt;10ms (no yield points)
    SM-&gt;&gt;SM: Detects long-running G
    SM-&gt;&gt;G: Send SIGURG
    Note over G: Signal handler fires, saves state
    G-&gt;&gt;S: Suspended
    S-&gt;&gt;S: Schedule next goroutine
    S-&gt;&gt;G: Re-schedule eventually</pre></figure>
<h2 id="choosing-the-right-pattern">Choosing the Right Pattern<a class="h-anchor" href="#choosing-the-right-pattern" aria-hidden="true" tabindex="-1"></a></h2>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    A{"Need\nconcurrency?"}
    A --&gt;|No| B["for {} loop\n(direct execution)"]
    A --&gt;|Yes| C{"Bounded\nwork?"}
    C --&gt;|Yes| D["Worker Pool\n(fixed goroutines)"]
    C --&gt;|No| E{"I/O or\nCPU bound?"}
    E --&gt;|I/O| F["Goroutine per task\n(scheduler handles blocking)"]
    E --&gt;|CPU| G["select {} loop\n(controlled yielding)"]</pre></figure>
<p>For most apps, use goroutines everywhere. For the 5% of performance-critical code, choose based on your scheduler profile.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Software Architecture: The Hard Parts</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2025-05-18:books/software-architecture-hard-parts</guid>
      <pubDate>Sun, 18 May 2025 00:00:00 GMT</pubDate>
      <category>books</category>
    </item>
    <item>
      <title>Review Your Own PR First</title>
      <link>https://ashwingopalsamy.in/library/notes/review-your-own-pr-first/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/review-your-own-pr-first/</guid>
      <pubDate>Wed, 15 Jan 2025 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>The PRs that merge cleanly are the ones authors already self-reviewed. A practical checklist before you ask.</description>
      <content:encoded><![CDATA[<p>Like most developers, I’ve been on both sides of Pull Requests. What I’ve noticed is that the best PRs, the ones that get merged smoothly with minimal back-and-forth, are where the author has already done a thorough self-review.</p>
<h2 id="what-happens-without-self-review">What Happens Without Self-Review<a class="h-anchor" href="#what-happens-without-self-review" aria-hidden="true" tabindex="-1"></a></h2>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">sequenceDiagram
    participant Author
    participant Reviewer
    Author-&gt;&gt;Reviewer: Push PR for review
    Reviewer-&gt;&gt;Author: 12 comments (typos, dead code, naming)
    Author-&gt;&gt;Author: Fix trivial issues
    Author-&gt;&gt;Reviewer: Push fixes
    Reviewer-&gt;&gt;Author: 5 more comments
    Author-&gt;&gt;Author: Fix again
    Author-&gt;&gt;Reviewer: Push fixes
    Note over Author,Reviewer: 3+ round trips before merge</pre></figure>
<h2 id="why-self-review-matters">Why Self-Review Matters<a class="h-anchor" href="#why-self-review-matters" aria-hidden="true" tabindex="-1"></a></h2>
<h3 id="a-saves-time">a. Saves Time<a class="h-anchor" href="#a-saves-time" aria-hidden="true" tabindex="-1"></a></h3>
<p>Clean up obvious issues yourself so reviewers focus on architecture and design.</p>
<h3 id="b-improves-code-quality">b. Improves Code Quality<a class="h-anchor" href="#b-improves-code-quality" aria-hidden="true" tabindex="-1"></a></h3>
<p>Reading your own diff catches patterns that don’t jump out when you’re writing.</p>
<h3 id="c-builds-trust">c. Builds Trust<a class="h-anchor" href="#c-builds-trust" aria-hidden="true" tabindex="-1"></a></h3>
<p>A polished PR signals respect for your colleagues’ time.</p>
<h2 id="how-to-self-review">How to Self-Review<a class="h-anchor" href="#how-to-self-review" aria-hidden="true" tabindex="-1"></a></h2>
<h3 id="a-view-the-diff-as-someone-else">a. View the Diff As Someone Else<a class="h-anchor" href="#a-view-the-diff-as-someone-else" aria-hidden="true" tabindex="-1"></a></h3>
<p>Open the Files changed tab and read every line as the reviewer.</p>
<h3 id="b-check-commit-messages">b. Check Commit Messages<a class="h-anchor" href="#b-check-commit-messages" aria-hidden="true" tabindex="-1"></a></h3>
<p>Follow conventional-commit style. Each commit should represent one logical change.</p>
<h3 id="c-document-special-considerations">c. Document Special Considerations<a class="h-anchor" href="#c-document-special-considerations" aria-hidden="true" tabindex="-1"></a></h3>
<p>Add inline comments for non-obvious decisions.</p>
<h3 id="d-validate-tests">d. Validate Tests<a class="h-anchor" href="#d-validate-tests" aria-hidden="true" tabindex="-1"></a></h3>
<p>Run them locally. Check coverage for success and failure paths.</p>
<h3 id="e-check-style-and-linting">e. Check Style and Linting<a class="h-anchor" href="#e-check-style-and-linting" aria-hidden="true" tabindex="-1"></a></h3>
<p>Run your formatter and linter before requesting review.</p>
<h2 id="what-happens-with-self-review">What Happens With Self-Review<a class="h-anchor" href="#what-happens-with-self-review" aria-hidden="true" tabindex="-1"></a></h2>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">sequenceDiagram
    participant Author
    participant Self as Self-Review
    participant Reviewer
    Author-&gt;&gt;Self: Read own diff as reviewer
    Self-&gt;&gt;Author: Catch 12 trivial issues locally
    Author-&gt;&gt;Author: Fix naming, dead code, edge cases
    Author-&gt;&gt;Reviewer: Push clean PR
    Reviewer-&gt;&gt;Author: 1 substantive design comment
    Author-&gt;&gt;Author: Address feedback
    Author-&gt;&gt;Reviewer: Push final fix
    Note over Author,Reviewer: 1 round trip to merge</pre></figure>
<h2 id="self-review-checklist">Self-Review Checklist<a class="h-anchor" href="#self-review-checklist" aria-hidden="true" tabindex="-1"></a></h2>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph TD
    Start["Open your PR diff"] --&gt; A{"Diff readable?\nClear naming?"}
    A --&gt;|Yes| B{"Commit messages\nclear and atomic?"}
    A --&gt;|No| A1["Fix naming"] --&gt; A
    B --&gt;|Yes| C{"Tests pass?\nCoverage adequate?"}
    B --&gt;|No| B1["Rewrite commits"] --&gt; B
    C --&gt;|Yes| D{"Docs updated?\nPR description clear?"}
    C --&gt;|No| C1["Add tests"] --&gt; C
    D --&gt;|Yes| E{"Linting clean?"}
    D --&gt;|No| D1["Update docs"] --&gt; D
    E --&gt;|Yes| F["Ready for review"]
    E --&gt;|No| E1["Run linter"] --&gt; E</pre></figure>
<p>The simplest habit that pays the biggest dividends: before clicking “Request Review”, open the Files changed tab and read every line as if a colleague wrote it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>The comparable Constraint in Go Generics</title>
      <link>https://ashwingopalsamy.in/library/notes/go-generics-comparable-constraint/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/go-generics-comparable-constraint/</guid>
      <pubDate>Wed, 25 Dec 2024 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>What &apos;incomparable types in type set&apos; means and how Go&apos;s comparable constraint shapes generic maps and sets.</description>
      <content:encoded><![CDATA[<p>While working on a generic function in Go, I once encountered this error: <em>‘incomparable types in type set’</em>.</p>
<p>It led me to dig deeper into the <code>comparable</code> constraint. With this post, I’ll walk you through what <code>comparable</code> is, why it’s useful, and how you can leverage it for cleaner, type-safe Go code.</p>
<h2 id="why-comparable">Why comparable?<a class="h-anchor" href="#why-comparable" aria-hidden="true" tabindex="-1"></a></h2>
<p><code>comparable</code> is a constraint that ensures a type supports equality comparisons (<code>==</code> and <code>!=</code>).</p>
<p>In Go, only certain types are inherently comparable: primitive types like <code>int</code>, <code>float64</code> and <code>string</code>, but exclude types like slices, maps, and functions.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">type</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657"> Array</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">[</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657"> comparable</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">] </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">struct</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    data []</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> (</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">a </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">*</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">Array</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">[</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">]) </span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Contains</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">value</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657"> T</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">bool</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    for</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> _, v </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> range</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> a.data {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">        if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> v </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">==</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> value {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">            return</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> true</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        }</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    return</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> false</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<h3 id="constraint-hierarchy">Constraint Hierarchy<a class="h-anchor" href="#constraint-hierarchy" aria-hidden="true" tabindex="-1"></a></h3>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph TD
    A["any\n(all types)"]
    B["comparable\n(supports == and !=)"]
    C["constraints.Ordered\n(supports &lt; &gt; &lt;= &gt;=)"]
    A --&gt; B
    B --&gt; C</pre></figure>
<h3 id="any-vs-interface">any vs. interface{}<a class="h-anchor" href="#any-vs-interface" aria-hidden="true" tabindex="-1"></a></h3>
<p><code>any</code> is simply an alias for <code>interface{}</code>. While functionally identical, <code>any</code> better aligns with the intentions of generics and improves readability.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> PrintValues</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">[</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657"> any</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">](</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">values</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> []</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    for</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> _, v </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> range</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> values {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Println</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(v)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<h3 id="real-world-scenarios">Real-World Scenarios<a class="h-anchor" href="#real-world-scenarios" aria-hidden="true" tabindex="-1"></a></h3>
<h4 id="1-deduplication-with-comparable">1. Deduplication with comparable<a class="h-anchor" href="#1-deduplication-with-comparable" aria-hidden="true" tabindex="-1"></a></h4>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> RemoveDuplicates</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">[</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657"> comparable</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">](</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">input</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> []</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) []</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    seen </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> make</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">map</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">[</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">]</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">bool</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    result </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> []</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">T</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">{}</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    for</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> _, v </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> range</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> input {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">        if</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> !</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">seen[v] {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">            seen[v] </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> true</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">            result </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">=</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> append</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(result, v)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        }</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    return</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> result</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<h3 id="compile-time-vs-runtime">Compile-Time vs Runtime<a class="h-anchor" href="#compile-time-vs-runtime" aria-hidden="true" tabindex="-1"></a></h3>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    subgraph "Using any (unsafe)"
        A1["func Contains\n[T any]"] --&gt; B1["Pass []int\nas T"]
        B1 --&gt; C1["Runtime Panic\n== on slice"]
    end
    subgraph "Using comparable (safe)"
        A2["func Contains\n[T comparable]"] --&gt; B2["Pass []int\nas T"]
        B2 --&gt; C2["Compile Error\n[]int not comparable"]
    end</pre></figure>
<p>The real value of <code>comparable</code> is catching errors at compile time instead of letting them slip into production.</p>
]]></content:encoded>
    </item>
    <item>
      <title>What Happens Before main() in Go</title>
      <link>https://ashwingopalsamy.in/library/notes/go-program-entry-point/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/go-program-entry-point/</guid>
      <pubDate>Fri, 13 Dec 2024 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>What the Go runtime does before main(): package init order, init functions, and startup orchestration.</description>
      <content:encoded><![CDATA[<p>When we first start with Go, the <code>main</code> function seems almost too simple. But before <code>main</code> even begins, the Go runtime orchestrates careful initialization of all imported packages, runs their <code>init</code> functions and ensures everything is in the right order.</p>
<h3 id="program-startup-sequence">Program Startup Sequence<a class="h-anchor" href="#program-startup-sequence" aria-hidden="true" tabindex="-1"></a></h3>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">sequenceDiagram
    participant OS
    participant Runtime
    participant Packages
    participant main
<!--diagram-blank-->
    OS-&gt;&gt;Runtime: Execute binary
    Runtime-&gt;&gt;Runtime: Bootstrap (scheduler, GC, memory)
    Runtime-&gt;&gt;Packages: Init packages in dependency order
    Packages-&gt;&gt;Packages: Run init() functions
    Packages--&gt;&gt;Runtime: All packages initialized
    Runtime-&gt;&gt;main: Call main()
    main-&gt;&gt;main: Main goroutine runs
    main--&gt;&gt;OS: os.Exit or return</pre></figure>
<h3 id="package-dependency-ordering">Package Dependency Ordering<a class="h-anchor" href="#package-dependency-ordering" aria-hidden="true" tabindex="-1"></a></h3>
<p>Go initializes packages in dependency order, not import order. Leaf packages initialize first.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph TD
    main["main\n(init last)"]
    A["Package A"]
    B["Package B"]
    C["Package C"]
    main --&gt; A
    main --&gt; B
    A --&gt; C</pre></figure>
<p>Init order: C -&gt; A -&gt; B -&gt; main.</p>
<h3 id="multiple-init-functions">Multiple init Functions<a class="h-anchor" href="#multiple-init-functions" aria-hidden="true" tabindex="-1"></a></h3>
<p>You can have multiple <code>init</code> functions. They run in order they appear. Go initializes packages in the order of their dependencies.</p>
<blockquote>
<p>Use <code>sync.Once</code> when you need lazy or guarded initialization of shared resources. It’s safer than relying on <code>init()</code> ordering.</p>
</blockquote>
<h3 id="exiting-with-osexit">Exiting with os.Exit()<a class="h-anchor" href="#exiting-with-osexit" aria-hidden="true" tabindex="-1"></a></h3>
<p><code>os.Exit()</code> terminates the program immediately. No deferred functions run.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> main</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">() {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> err </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> doSomethingRisky</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(); err </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">!=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> nil</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">        cleanup</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">()</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        os.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Exit</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">1</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<h3 id="the-main-goroutine">The main Goroutine<a class="h-anchor" href="#the-main-goroutine" aria-hidden="true" tabindex="-1"></a></h3>
<p>The <code>main</code> function runs in a special goroutine. If <code>main</code> returns, the entire program exits – even if other goroutines are still working. Use <code>sync.WaitGroup</code> to wait for background goroutines.</p>
]]></content:encoded>
    </item>
    <item>
      <title>The Art of Doing Science and Engineering</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2024-12-01:books/art-of-doing-science-engineering</guid>
      <pubDate>Sun, 01 Dec 2024 00:00:00 GMT</pubDate>
      <category>books</category>
    </item>
    <item>
      <title>Go Pointers and Memory Management</title>
      <link>https://ashwingopalsamy.in/library/notes/go-pointers-and-memory-management/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/go-pointers-and-memory-management/</guid>
      <pubDate>Sun, 17 Nov 2024 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>A practical look at Go pointers, escape analysis, and how the runtime keeps memory both efficient and safe.</description>
      <content:encoded><![CDATA[<p>When I first started learning Go, I was intrigued by its approach to memory management. Go handles memory in a way that’s both efficient and safe, but it can be a bit of a black box if you don’t peek under the hood.</p>
<h2 id="understanding-stack-and-heap-memory">Understanding Stack and Heap Memory<a class="h-anchor" href="#understanding-stack-and-heap-memory" aria-hidden="true" tabindex="-1"></a></h2>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph TD
    subgraph STACK["Goroutine Stack"]
        S1["Local variables"]
        S2["Function parameters"]
        S3["Return addresses"]
    end
    subgraph HEAP["Shared Heap"]
        H1["Escaped variables"]
        H2["Pointers returned\nfrom functions"]
        H3["Closure captures"]
    end
    EA{{"Escape Analysis\n(compile time)"}}
    EA -- "does not escape" --&gt; STACK
    EA -- "escapes to heap" --&gt; HEAP</pre></figure>
<h2 id="passing-by-value-the-default-behavior">Passing by Value: The Default Behavior<a class="h-anchor" href="#passing-by-value-the-default-behavior" aria-hidden="true" tabindex="-1"></a></h2>
<p>In Go, when you pass variables like integer, string, or boolean to a function, they are passed by value. A copy is made.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> increment</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">num</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> int</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    num</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">++</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> main</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">() {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    n </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 21</span></span>
<span class="line"><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">    increment</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(n)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Println</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(n) </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// 21</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<h2 id="introducing-pointers">Introducing Pointers<a class="h-anchor" href="#introducing-pointers" aria-hidden="true" tabindex="-1"></a></h2>
<p>To modify the original variable inside a function, pass a pointer.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> incrementPointer</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">num</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> *int</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    (</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">*</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">num)</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">++</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> main</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">() {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    n </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 42</span></span>
<span class="line"><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">    incrementPointer</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">&amp;</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">n)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Println</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(n) </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// 43</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<h2 id="escape-analysis">Escape Analysis<a class="h-anchor" href="#escape-analysis" aria-hidden="true" tabindex="-1"></a></h2>
<p>Escape analysis determines whether variables need to live beyond their function scope.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">flowchart TD
    A["Variable declared"] --&gt; B{"Returned as\npointer?"}
    B -- Yes --&gt; HEAP["Allocate on Heap"]
    B -- No --&gt; C{"Captured by\nclosure?"}
    C -- Yes --&gt; HEAP
    C -- No --&gt; D{"Assigned to\ninterface?"}
    D -- Yes --&gt; HEAP
    D -- No --&gt; E{"Too large\nfor stack?"}
    E -- Yes --&gt; HEAP
    E -- No --&gt; STACK["Allocate on Stack"]</pre></figure>
<p>Run <code>go build -gcflags '-m'</code> on any Go file to see escape analysis decisions.</p>
<h2 id="concurrency-issues--data-race">Concurrency Issues – Data Race<a class="h-anchor" href="#concurrency-issues--data-race" aria-hidden="true" tabindex="-1"></a></h2>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> main</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">() {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    var</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> wg </span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">sync</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">.</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">WaitGroup</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    counter </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 0</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    counterPtr </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> &amp;</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">counter</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    for</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> i </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 0</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">; i </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">&lt;</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 1000</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">; i</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">++</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        wg.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Add</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">1</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">)</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">        go</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> func</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">() {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">            *</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">counterPtr</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">++</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">            wg.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Done</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">()</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        }()</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    wg.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Wait</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">()</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Println</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"Counter:"</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">*</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">counterPtr)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<p>This has a data race. Fix with a mutex:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">var</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> mu </span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">sync</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">.</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">Mutex</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">go</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> func</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">() {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    mu.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Lock</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">()</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    *</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">counterPtr</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">++</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    mu.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Unlock</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">()</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    wg.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Done</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">()</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}()</span></span></code></pre></div>
<h2 id="key-takeaways">Key Takeaways<a class="h-anchor" href="#key-takeaways" aria-hidden="true" tabindex="-1"></a></h2>
<ul>
<li>Passing by value is simple but can be inefficient for large data structures</li>
<li>Using pointers avoids copying but requires synchronization for shared access</li>
<li>Escape analysis determines stack vs heap allocation</li>
<li>Go prevents dangling pointers via garbage collection</li>
<li>Run <code>go test -race</code> to detect data races</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>The Office</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2024-11-15:watch/the-office</guid>
      <pubDate>Fri, 15 Nov 2024 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Git Practices for Production Codebases</title>
      <link>https://ashwingopalsamy.in/library/notes/git-practices-for-production-codebases/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/git-practices-for-production-codebases/</guid>
      <pubDate>Thu, 14 Nov 2024 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>Git habits that hold up in FinTech production: shared language, safety nets, and reviewable history.</description>
      <content:encoded><![CDATA[<p>Git is the backbone of every software project. Working in FinTech systems, I’ve learned that Git isn’t just a tool – it’s a shared language and a safety net.</p>
<blockquote>
<p>In FinTech and regulated environments, every change must be auditable and traceable. Clean Git practices are not just about developer productivity – they are a compliance requirement.</p>
</blockquote>
<h2 id="commits">Commits<a class="h-anchor" href="#commits" aria-hidden="true" tabindex="-1"></a></h2>
<h3 id="1-write-atomic-commits">1. Write Atomic Commits<a class="h-anchor" href="#1-write-atomic-commits" aria-hidden="true" tabindex="-1"></a></h3>
<p>An atomic commit focuses on one thing – fixing a bug, adding a feature, or refactoring.</p>
<p>Good: <code>feat: add endpoint for retrieving user account balances</code>
Bad: <code>misc: fix bugs and add features</code></p>
<h3 id="2-use-descriptive-commit-messages">2. Use Descriptive Commit Messages<a class="h-anchor" href="#2-use-descriptive-commit-messages" aria-hidden="true" tabindex="-1"></a></h3>
<div class="code-figure" data-language="plaintext"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>&lt;type&gt;(&lt;scope&gt;): &lt;subject&gt;</span></span>
<span class="line"><span>&lt;BLANK LINE&gt;</span></span>
<span class="line"><span>&lt;body (optional)&gt;</span></span></code></pre></div>
<blockquote>
<p>The Conventional Commits Specification formalizes this format. It pairs well with commitlint and enables automatic changelog generation.</p>
</blockquote>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    A["feat(parser): add bitmap validation"]
    A --&gt; B["&lt;b&gt;type&lt;/b&gt;&lt;br/&gt;feat"]
    A --&gt; C["&lt;b&gt;scope&lt;/b&gt;&lt;br/&gt;parser"]
    A --&gt; D["&lt;b&gt;description&lt;/b&gt;&lt;br/&gt;add bitmap validation"]</pre></figure>
<h2 id="branches">Branches<a class="h-anchor" href="#branches" aria-hidden="true" tabindex="-1"></a></h2>
<h3 id="1-follow-a-consistent-naming-convention">1. Follow a Consistent Naming Convention<a class="h-anchor" href="#1-follow-a-consistent-naming-convention" aria-hidden="true" tabindex="-1"></a></h3>
<div class="code-figure" data-language="plaintext"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>&lt;JIRA-ticket-ID&gt;-&lt;type&gt;-&lt;short-description&gt;</span></span></code></pre></div>
<p>Examples: <code>JIRA-5678-fix-transaction-timeout</code>, <code>JIRA-1234-feature-add-batch-processing</code></p>
<h3 id="2-rebase-for-a-clean-history">2. Rebase for a Clean History<a class="h-anchor" href="#2-rebase-for-a-clean-history" aria-hidden="true" tabindex="-1"></a></h3>
<div class="code-figure" data-language="bash"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="--shiki-light:#953800;--shiki-dark:#FFA657">git</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> checkout</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> JIRA-5678-fix-transaction-timeout</span></span>
<span class="line"><span style="--shiki-light:#953800;--shiki-dark:#FFA657">git</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> pull</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> --rebase</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> origin</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> main</span></span></code></pre></div>
<blockquote>
<p>Rebasing rewrites commit hashes, so it should only be used on local or feature branches. The payoff is a linear history that reads like a narrative.</p>
</blockquote>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">gitGraph
    commit id: "init"
    commit id: "v1.0"
    branch JIRA-5678-fix-timeout
    commit id: "add retry logic"
    commit id: "handle edge case"
    commit id: "add tests"
    checkout main
    commit id: "hotfix: logging"
    checkout JIRA-5678-fix-timeout
    merge main id: "rebase onto main" type: HIGHLIGHT
    checkout main
    merge JIRA-5678-fix-timeout id: "squash merge" type: HIGHLIGHT
    commit id: "v1.1"</pre></figure>
<h2 id="pull-requests">Pull Requests<a class="h-anchor" href="#pull-requests" aria-hidden="true" tabindex="-1"></a></h2>
<h3 id="1-use-clear-pr-titles">1. Use Clear PR Titles<a class="h-anchor" href="#1-use-clear-pr-titles" aria-hidden="true" tabindex="-1"></a></h3>
<p><code>[JIRA-ticket-ID] &lt;Type&gt;: &lt;Short Description&gt;</code></p>
<p>Examples:</p>
<ul>
<li><code>[JIRA-5678] Fix: Handle transaction timeout edge cases</code></li>
<li><code>[JIRA-1234] Feature: Add bulk processing for transactions</code></li>
</ul>
<h3 id="2-write-pr-descriptions">2. Write PR Descriptions<a class="h-anchor" href="#2-write-pr-descriptions" aria-hidden="true" tabindex="-1"></a></h3>
<p>Answer three questions: What changed? Why? Does it introduce risks?</p>
<h3 id="3-keep-prs-small">3. Keep PRs Small<a class="h-anchor" href="#3-keep-prs-small" aria-hidden="true" tabindex="-1"></a></h3>
<p>Large PRs are hard to review and prone to mistakes. A schema migration should be its own PR.</p>
<h3 id="4-self-review-first">4. Self-Review First<a class="h-anchor" href="#4-self-review-first" aria-hidden="true" tabindex="-1"></a></h3>
<p>Read your diff as if a colleague wrote it before requesting review.</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    A["Branch Created"] --&gt; B["Commits"]
    B --&gt; C["Self-Review"]
    C --&gt; D["PR Opened"]
    D --&gt; E["CI Passes"]
    E --&gt; F["Code Review"]
    F --&gt; G["Approved"]
    G --&gt; H["Squash Merge"]
    H --&gt; I["Branch Deleted"]</pre></figure>
<p>In highly critical FinTech systems, precision isn’t optional. Clean commits, structured branches, and clear PRs are safeguards for the stability of the systems we build.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Go Constants Beyond the Basics</title>
      <link>https://ashwingopalsamy.in/library/notes/go-constants-beyond-basics/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/go-constants-beyond-basics/</guid>
      <pubDate>Wed, 13 Nov 2024 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>Go constants are fixed values with surprising flexibility: typed constants, iota, and compile-time tricks that matter.</description>
      <content:encoded><![CDATA[<p>When I first got into Go, I thought constants were simple and limited – just fixed values, nothing fancy. But as I delved deeper, I found they’re quite versatile. Yes, they’re fixed values, but Go handles them in ways that are both flexible and efficient. Let’s see what that means with some practical examples.</p>
<h2 id="constants-as-type-free-values-until-theyre-used">Constants as Type-Free Values (Until They’re Used)<a class="h-anchor" href="#constants-as-type-free-values-until-theyre-used" aria-hidden="true" tabindex="-1"></a></h2>
<p>In Go, constants are often untyped until you actually use them. They have a default kind but can be assigned to variables of different types, as long as the value fits. This makes them adaptable in a way that’s unusual for a statically typed language.</p>
<p>Here’s how that looks:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> x</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 10</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">var</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> i </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">int</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> x</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">var</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> f </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">float64</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> x</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">var</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> b </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">byte</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> x</span></span></code></pre></div>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph TD
    A["const x = 5\n(untyped)"] --&gt; B["used as int"]
    A --&gt; C["used as float64"]
    A --&gt; D["used as byte"]
    B --&gt; E["int"]
    C --&gt; F["float64"]
    D --&gt; G["byte"]</pre></figure>
<p>A bit analogous to Schrodinger’s paradox, <code>x</code> can be an <code>int</code>, a <code>float64</code>, or even a <code>byte</code> until you assign it. This temporary flexibility lets <code>x</code> work smoothly with different types in your code. No need for casting, which keeps things neat.</p>
<p>You can even mix constants of different types in expressions and Go will figure out the best type for the result:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> a</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 1.5</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> b</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 2</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> result</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> a </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">*</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> b </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// result is float64</span></span></code></pre></div>
<p>Since <code>a</code> is a floating-point number, Go promotes the whole expression to <code>float64</code>. So you don’t have to worry about losing precision – Go handles it. But be careful: if you try to assign <code>result</code> to an <code>int</code>, you’ll get an error. Go doesn’t allow implicit conversions that might lose data.</p>
<h2 id="constants-in-conditional-compilation">Constants in Conditional Compilation<a class="h-anchor" href="#constants-in-conditional-compilation" aria-hidden="true" tabindex="-1"></a></h2>
<p>Go doesn’t have a preprocessor like some other languages, but you can use constants in <code>if</code> statements to include or exclude code at compile time.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> debug</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> false</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> main</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">() {</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">    if</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> debug {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">        fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Println</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"Debugging enabled"</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    }</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<p>When <code>debug</code> is <code>false</code>, the compiler knows the <code>if</code> condition will never be true and might leave out the code inside the block. This can make your final binary smaller.</p>
<h2 id="working-with-big-numbers">Working with Big Numbers<a class="h-anchor" href="#working-with-big-numbers" aria-hidden="true" tabindex="-1"></a></h2>
<p>One powerful feature of Go’s constants is that they support very large numbers. Untyped numeric constants in Go have “infinite” precision, limited only by memory and the compiler.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> bigNum</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 1</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">e</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">1000</span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E"> // This is a valid constant</span></span></code></pre></div>
<p>Even though <code>bigNum</code> is way bigger than any built-in numeric type like <code>float64</code> or <code>int</code>, Go lets you define it as a constant. You can do calculations with these large numbers at compile time:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> (</span></span>
<span class="line"><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">    a</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 1</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">e</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">20</span></span>
<span class="line"><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">    b</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 1</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">e</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">30</span></span>
<span class="line"><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">    c</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> a </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">*</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> b </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// c is 1e50</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">)</span></span></code></pre></div>
<h2 id="typed-constants-with-iota">Typed Constants with iota<a class="h-anchor" href="#typed-constants-with-iota" aria-hidden="true" tabindex="-1"></a></h2>
<p>If you’ve been using Go, you’ve probably seen <code>iota</code> for creating enumerated constants.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> (</span></span>
<span class="line"><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">    _</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> iota</span></span>
<span class="line"><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">    KB</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 1</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> &lt;&lt;</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> (</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">10</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> *</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> iota</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">)</span></span>
<span class="line"><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">    MB</span></span>
<span class="line"><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">    GB</span></span>
<span class="line"><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">    TB</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">)</span></span></code></pre></div>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    A["iota=0"] --&gt; B["1&lt;&lt;0 = 1\n(Read)"]
    C["iota=1"] --&gt; D["1&lt;&lt;1 = 2\n(Write)"]
    E["iota=2"] --&gt; F["1&lt;&lt;2 = 4\n(Execute)"]
    B --&gt; G["Read | Write = 3"]
    D --&gt; G</pre></figure>
<h2 id="limitations-with-constants">Limitations with Constants<a class="h-anchor" href="#limitations-with-constants" aria-hidden="true" tabindex="-1"></a></h2>
<p>While Go’s constants are flexible, there are some things they can’t do.</p>
<h3 id="1-constants-cannot-be-referenced-by-pointers">1. Constants Cannot Be Referenced by Pointers<a class="h-anchor" href="#1-constants-cannot-be-referenced-by-pointers" aria-hidden="true" tabindex="-1"></a></h3>
<p>Constants don’t have a memory address at runtime. So you can’t take the address of a constant or use a pointer to it.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> x</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 10</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">var</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> p </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">=</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> &amp;</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">x </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// Error: cannot take the address of x</span></span></code></pre></div>
<h3 id="2-function-calls-in-constant-declarations">2. Function Calls in Constant Declarations<a class="h-anchor" href="#2-function-calls-in-constant-declarations" aria-hidden="true" tabindex="-1"></a></h3>
<p>Only certain built-in functions can be used in constant expressions, like <code>len</code>, <code>cap</code>, <code>real</code>, <code>imag</code>, and <code>complex</code>.</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> str</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> "hello"</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> length</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> len</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(str) </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// This works</span></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">const</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> pow</span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72"> =</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3"> math.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Pow</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">2</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, </span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF">3</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">) </span><span style="--shiki-light:#6E7781;--shiki-dark:#8B949E">// Error: math.Pow cannot be used in constant expressions</span></span></code></pre></div>
]]></content:encoded>
    </item>
    <item>
      <title>Go&apos;s UTF-8 Identifier Limitation</title>
      <link>https://ashwingopalsamy.in/library/notes/go-utf8-identifier-limitation/</link>
      <guid isPermaLink="true">https://ashwingopalsamy.in/library/notes/go-utf8-identifier-limitation/</guid>
      <pubDate>Tue, 12 Nov 2024 00:00:00 GMT</pubDate>
      <category>notes</category>
      <description>Where Go&apos;s UTF-8 support stops: what works in identifiers, and what non-Latin scripts still can&apos;t do.</description>
      <content:encoded><![CDATA[<p>I’ve been exploring Go’s UTF-8 support and was curious about how well it handles non-Latin scripts in code.</p>
<p>Go source files are UTF-8 encoded by default. You can use Unicode characters in variable names and function names. Chinese characters work fine:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">package</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657"> main</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">import</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> "</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">fmt</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> main</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">() {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    消息 </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> "Hello, World!"</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Println</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(消息)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<h2 id="attempting-to-use-tamil-identifiers">Attempting to Use Tamil Identifiers<a class="h-anchor" href="#attempting-to-use-tamil-identifiers" aria-hidden="true" tabindex="-1"></a></h2>
<p>I tried Tamil, my mother tongue:</p>
<div class="code-figure" data-language="go"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="go"><code><span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">package</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657"> main</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">import</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF"> "</span><span style="--shiki-light:#953800;--shiki-dark:#FFA657">fmt</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">func</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF"> main</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">() {</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    எண்ணிக்கை </span><span style="--shiki-light:#CF222E;--shiki-dark:#FF7B72">:=</span><span style="--shiki-light:#0550AE;--shiki-dark:#79C0FF"> 42</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">    fmt.</span><span style="--shiki-light:#8250DF;--shiki-dark:#D2A8FF">Println</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">(</span><span style="--shiki-light:#0A3069;--shiki-dark:#A5D6FF">"Value:"</span><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">, எண்ணிக்கை)</span></span>
<span class="line"><span style="--shiki-light:#1F2328;--shiki-dark:#E6EDF3">}</span></span></code></pre></div>
<p>But the compiler throws errors:</p>
<div class="code-figure" data-language="plaintext"><pre class="astro-code astro-code-themes github-light-default github-dark-default" style="--shiki-light:#1f2328;--shiki-dark:#e6edf3;--shiki-light-bg:#ffffff;--shiki-dark-bg:#0d1117; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>./prog.go:6:11: invalid character U+0BCD '்' in identifier</span></span></code></pre></div>
<h3 id="why-combining-marks-fail">Why Combining Marks Fail<a class="h-anchor" href="#why-combining-marks-fail" aria-hidden="true" tabindex="-1"></a></h3>
<p>Tamil is an abugida. Consonant-vowel sequences are written as units with combining marks. Go’s spec allows Unicode letters in identifiers but excludes combining marks (categories <code>Mn</code>, <code>Mc</code>, <code>Me</code>).</p>
<figure class="diagram" data-diagram><div class="diagram-canvas" role="img" aria-label="Mermaid diagram"></div><pre class="diagram-source">graph LR
    A["Tamil syllable"] --&gt; B["Base consonant\n(Lo: valid)"]
    A --&gt; C["Vowel sign\n(Mc: continuation only)"]
    B --&gt; D["Visually incomplete\nalone"]
    C --&gt; D</pre></figure>
<h3 id="chinese-vs-tamil">Chinese vs Tamil<a class="h-anchor" href="#chinese-vs-tamil" aria-hidden="true" tabindex="-1"></a></h3>
<p>Chinese characters are classified under “Letter, Other” (<code>Lo</code>) – standalone symbols. Tamil requires combining marks, which Go’s spec explicitly excludes.</p>
<blockquote>
<p>Go’s creators primarily aimed for consistent string handling through UTF-8 support. They didn’t necessarily intend for native-language coding in identifiers requiring combining marks.</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>Avatar: The Last Airbender</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2024-07-20:watch/avatar-the-last-airbender</guid>
      <pubDate>Sat, 20 Jul 2024 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Learning Go</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2024-06-10:books/learning-go</guid>
      <pubDate>Mon, 10 Jun 2024 00:00:00 GMT</pubDate>
      <category>books</category>
    </item>
    <item>
      <title>Chotta Bheem</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2024-05-01:watch/chotta-bheem</guid>
      <pubDate>Wed, 01 May 2024 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Suits</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2024-03-10:watch/suits</guid>
      <pubDate>Sun, 10 Mar 2024 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>The Social Network</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2024-01-20:watch/the-social-network</guid>
      <pubDate>Sat, 20 Jan 2024 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>BoJack Horseman</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2023-10-14:watch/bojack-horseman</guid>
      <pubDate>Sat, 14 Oct 2023 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Breaking Bad</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2023-08-14:watch/breaking-bad</guid>
      <pubDate>Mon, 14 Aug 2023 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Never Have I Ever</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2023-06-08:watch/never-have-i-ever</guid>
      <pubDate>Thu, 08 Jun 2023 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Ben 10</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2023-02-12:watch/ben-10</guid>
      <pubDate>Sun, 12 Feb 2023 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Vikings</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2022-09-30:watch/vikings</guid>
      <pubDate>Fri, 30 Sep 2022 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Money Heist</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2021-12-03:watch/money-heist</guid>
      <pubDate>Fri, 03 Dec 2021 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Mr. Robot</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2020-08-22:watch/mr-robot</guid>
      <pubDate>Sat, 22 Aug 2020 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>13 Reasons Why</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2020-06-05:watch/13-reasons-why</guid>
      <pubDate>Fri, 05 Jun 2020 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Silicon Valley</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2020-05-01:watch/silicon-valley</guid>
      <pubDate>Fri, 01 May 2020 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Chernobyl</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2019-06-03:watch/chernobyl</guid>
      <pubDate>Mon, 03 Jun 2019 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
    <item>
      <title>Game of Thrones</title>
      <link>https://ashwingopalsamy.in/library/</link>
      <guid isPermaLink="false">tag:ashwingopalsamy.in,2019-05-20:watch/game-of-thrones</guid>
      <pubDate>Mon, 20 May 2019 00:00:00 GMT</pubDate>
      <category>watch</category>
    </item>
  </channel>
</rss>
