<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[That Catto’s Place]]></title><description><![CDATA[That Catto’s Place]]></description><link>https://blog.zackryrosli.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 21 May 2026 14:21:00 GMT</lastBuildDate><atom:link href="https://blog.zackryrosli.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The "Guardians" of the Concurrency]]></title><description><![CDATA[When diving into concurrent programming in Go, two fundamental synchronization primitives often come up: mutexes and semaphores. While they might seem similar at first glance, they serve different purposes and understanding when to use each is crucia...]]></description><link>https://blog.zackryrosli.com/the-guardians-of-the-concurrency</link><guid isPermaLink="true">https://blog.zackryrosli.com/the-guardians-of-the-concurrency</guid><category><![CDATA[Go Language]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Zack]]></dc:creator><pubDate>Mon, 17 Nov 2025 21:21:47 GMT</pubDate><content:encoded><![CDATA[<p>When diving into concurrent programming in Go, two fundamental synchronization primitives often come up: <strong>mutexes</strong> and <strong>semaphores</strong>. While they might seem similar at first glance, they serve different purposes and understanding when to use each is crucial for writing safe, efficient concurrent code.</p>
<p>In this post, we’ll explore both concepts through relatable analogies and practical Go examples. By the end, you’ll have a clear understanding of when to reach for a mutex versus a semaphore.</p>
<h2 id="heading-mutex-the-library-book">Mutex: The Library Book</h2>
<p>A <strong>mutex</strong> (short for “mutual exclusion“) is like a popular library book with only one copy. Only one person can check it out at a time, and they must return it before the next person can borrow it. When they’re done reading, they return the book to the library, and the next person in line can check it out.</p>
<p>In Go, a <code>sync.Mutex</code> ensures that only one goroutine can access a critical section of code at a time. It’s binary: locked or unlocked. There’s no middle ground.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

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

<span class="hljs-keyword">var</span> (
    counter <span class="hljs-keyword">int</span>
    mutex   sync.Mutex
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">increment</span><span class="hljs-params">()</span></span> {
    mutex.Lock()         <span class="hljs-comment">// Check out the book</span>
    <span class="hljs-keyword">defer</span> mutex.Unlock() <span class="hljs-comment">// Always return the book, even if panic occurs</span>

    <span class="hljs-comment">// Critical section: only one goroutine can be here at a time</span>
    temp := counter
    time.Sleep(<span class="hljs-number">1</span> * time.Millisecond) <span class="hljs-comment">// Simulate reading the book</span>
    counter = temp + <span class="hljs-number">1</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> wg sync.WaitGroup

    <span class="hljs-comment">// Launch 10 goroutines trying to increment</span>
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++ {
        wg.Add(<span class="hljs-number">1</span>)
        <span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
            <span class="hljs-keyword">defer</span> wg.Done()
            increment()
        }()
    }

    wg.Wait()
    fmt.Printf(<span class="hljs-string">"Final counter: %d\n"</span>, counter) <span class="hljs-comment">// Will always prints 10</span>
}
</code></pre>
<p>The mutex is the librarian managing the book checkout. It doesn't matter how many people want to read the book, only one person can have it at a time. Simple, predictable, and perfect when you need exclusive access.</p>
<h2 id="heading-semaphore-the-computer-lab">Semaphore: The Computer Lab</h2>
<p>A <strong>semaphore</strong>, on the other hand, is like a computer lab with 5 computers available. The lab monitor keeps track of how many computers are free. When a computer becomes available, the next student can use it. If all 5 computers are in use, new students must wait.</p>
<p>In Go, semaphores can be implemented using buffered channels (for educational purposes) or using the official <code>golang.org/x/sync/semaphore</code> package (for production use). They allow a specified number of goroutines to access a resource simultaneously, not just one.</p>
<h3 id="heading-understanding-semaphores-the-simple-way">Understanding Semaphores: The Simple Way</h3>
<p>Here's a simple semaphore implementation using a buffered channel to illustrate the concept. This example limits concurrent computer usage to manage lab resources:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

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

<span class="hljs-comment">// A semaphore implemented with a buffered channel</span>
<span class="hljs-keyword">type</span> Semaphore <span class="hljs-keyword">struct</span> {
    tokens <span class="hljs-keyword">chan</span> <span class="hljs-keyword">struct</span>{}
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewSemaphore</span><span class="hljs-params">(capacity <span class="hljs-keyword">int</span>)</span> *<span class="hljs-title">Semaphore</span></span> {
    <span class="hljs-keyword">return</span> &amp;Semaphore{
        tokens: <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">struct</span>{}, capacity),
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(s *Semaphore)</span> <span class="hljs-title">Acquire</span><span class="hljs-params">()</span></span> {
    s.tokens &lt;- <span class="hljs-keyword">struct</span>{}{} <span class="hljs-comment">// Take a token</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(s *Semaphore)</span> <span class="hljs-title">Release</span><span class="hljs-params">()</span></span> {
    &lt;-s.tokens <span class="hljs-comment">// Return the token</span>
}

<span class="hljs-keyword">var</span> sem = NewSemaphore(<span class="hljs-number">3</span>) <span class="hljs-comment">// // Limit to 3 concurrent computer users</span>

<span class="hljs-comment">// Simulate using a computer in the lab</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">useComputer</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>)</span></span> {
    sem.Acquire()         <span class="hljs-comment">// Get permission to use a computer</span>
    <span class="hljs-keyword">defer</span> sem.Release()   <span class="hljs-comment">// Return the computer when done</span>

    fmt.Printf(<span class="hljs-string">"Student %d: Using computer...\n"</span>, id)
    time.Sleep(<span class="hljs-number">100</span> * time.Millisecond) <span class="hljs-comment">// // Simulate work time</span>
    fmt.Printf(<span class="hljs-string">"Student %d: Finished using computer\n"</span>, id)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> wg sync.WaitGroup

    <span class="hljs-comment">// Tell 10 students to use computers</span>
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++ {
        wg.Add(<span class="hljs-number">1</span>)
        <span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>)</span></span> {
            <span class="hljs-keyword">defer</span> wg.Done()
            useComputer(id)
        }(i)
    }

    wg.Wait()
    fmt.Println(<span class="hljs-string">"All students finished using computers"</span>)
}
</code></pre>
<p>Notice how the semaphore controls the concurrency without needing a mutex? This is because we’re limiting access to an external resource (computers), not protecting shared mutable state. Only 3 students can use computers simultaneously, while the others wait.</p>
<h3 id="heading-production-ready-using-the-official-package">Production-Ready: Using the Official Package</h3>
<p>For production code, you should use the official <code>golang.org/x/sync/semaphore</code> package, which provides a weighted semaphore with context support and better performance:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

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

    <span class="hljs-string">"golang.org/x/sync/semaphore"</span>
)

<span class="hljs-keyword">var</span> sem = semaphore.NewWeighted(<span class="hljs-number">3</span>) <span class="hljs-comment">// Limit to 3 concurrent computer users</span>

<span class="hljs-comment">// Simulate using a computer in the lab</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">useComputer</span><span class="hljs-params">(ctx context.Context, id <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-keyword">if</span> err := sem.Acquire(ctx, <span class="hljs-number">1</span>); err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err <span class="hljs-comment">// Context cancelled or timeout</span>
    }
    <span class="hljs-keyword">defer</span> sem.Release(<span class="hljs-number">1</span>)

    fmt.Printf(<span class="hljs-string">"Student %d: Using computer...\n"</span>, id)
    time.Sleep(<span class="hljs-number">100</span> * time.Millisecond) <span class="hljs-comment">// Simulate work time</span>
    fmt.Printf(<span class="hljs-string">"Student %d: Finished using computer\n"</span>, id)
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    ctx := context.Background()
    <span class="hljs-keyword">var</span> wg sync.WaitGroup

    <span class="hljs-comment">// Tell 10 students to use computers</span>
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++ {
        wg.Add(<span class="hljs-number">1</span>)
        <span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>)</span></span> {
            <span class="hljs-keyword">defer</span> wg.Done()
            <span class="hljs-keyword">if</span> err := useComputer(ctx, id); err != <span class="hljs-literal">nil</span> {
                fmt.Printf(<span class="hljs-string">"Student %d: failed: %v\n"</span>, id, err)
            }
        }(i)
    }

    wg.Wait()
    fmt.Println(<span class="hljs-string">"All students finished using computers"</span>)
}
</code></pre>
<p>The official package offers additional benefits like context cancellation support (so you can timeout or cancel semaphore acquisition) and weighted acquisition (allowing different goroutines to request different amounts of capacity). This is perfect for rate limiting, connection pooling, or controlling access to resource pools.</p>
<h2 id="heading-the-moral-of-the-story">The Moral of the Story</h2>
<p>Both mutexes and semaphores are tools in your concurrency toolkit, each serving different purposes:</p>
<ul>
<li><p><strong>Mutex</strong>: “Only one at a time, please.”</p>
</li>
<li><p><strong>Semaphore</strong>: “We have N computers available, but no more.”</p>
</li>
</ul>
<p>Understanding when to use each is key to writing safe, efficient concurrent Go programs. The mutex is your strict bouncer, ensuring exclusive access. The semaphore is your capacity manager, controlling the flow while allowing controlled concurrency.</p>
<p>In the world of Go concurrency, both have their place. Choose wisely, and your programs will thank you with predictable behavior and optimal performance.</p>
]]></content:encoded></item><item><title><![CDATA[Should I use frameworks in Go?]]></title><description><![CDATA[We all know that Go is one of the popular programming languages for crafting fast and scalable web applications. If you are coming from another programming languages (such as JavaScript or PHP), you might prefer using frameworks to make everything ea...]]></description><link>https://blog.zackryrosli.com/should-i-use-frameworks-in-go</link><guid isPermaLink="true">https://blog.zackryrosli.com/should-i-use-frameworks-in-go</guid><category><![CDATA[Go Language]]></category><dc:creator><![CDATA[Zack]]></dc:creator><pubDate>Fri, 15 Mar 2024 23:29:24 GMT</pubDate><content:encoded><![CDATA[<p>We all know that Go is one of the popular programming languages for crafting fast and scalable web applications. If you are coming from another programming languages (such as JavaScript or PHP), you might prefer using frameworks to make everything easier for yourself. But to be honest, we don't need that in Go.</p>
<h2 id="heading-why-the-heck-not">Why the heck not?</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710544028462/b8ebe94f-a9be-43b0-a409-59c870c32607.png" alt class="image--center mx-auto" /></p>
<p><em>Enjoy my crap drawing LOL</em></p>
<p>When you have two frameworks, they both force you to fill in a specific hole. Usually, there is no way to fit one framework inside another. With packages, the situation is different. You are in control, so go crazy!</p>
<h2 id="heading-how-do-i-handle-url-parameters-and-methods">How do I handle URL parameters and methods?</h2>
<p>While Go's net/http package is comprehensive, the one thing it truly sucks at is handling URL parameters and providing an easy way to create handlers for specific methods. But hey, that is not the case anymore!</p>
<p>In Go 1.22, Go team introduced two <a target="_blank" href="https://go.dev/blog/routing-enhancements">enhancements</a> to the net/http package: method matching and wildcards. Yay!</p>
<p>Instead of writing this verbose code:</p>
<pre><code class="lang-go">m := http.NewServeMux()
m.HandleFunc(<span class="hljs-string">"/items/"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
    <span class="hljs-keyword">if</span> r.Method != http.MethodGet {
        w.WriteHeader(http.StatusMethodNotAllowed)
        <span class="hljs-keyword">return</span>
    }

    <span class="hljs-keyword">if</span> r.URL.Path == <span class="hljs-string">"/items/"</span> {
        w.WriteHeader(http.StatusNotFound)
        <span class="hljs-keyword">return</span>
    }

    w.Write([]<span class="hljs-keyword">byte</span>(strings.TrimPrefix(r.URL.Path, <span class="hljs-string">"/items/"</span>)))
})
</code></pre>
<p>You will get this pretty code instead :)</p>
<pre><code class="lang-go">m := http.NewServeMux()
m.HandleFunc(<span class="hljs-string">"GET /items/{id}"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
    w.Write([]<span class="hljs-keyword">byte</span>(r.PathValue(<span class="hljs-string">"id"</span>)))
})
</code></pre>
<h2 id="heading-i-heard-that-x-is-faster-so-why-shouldnt-i-learn-it">I heard that X is faster, so why shouldn't I learn it?!</h2>
<p>Fiber (based on FastHTTP), and many other alternatives, have numerous tradeoffs that make it hard for people to recommend their usage.</p>
<ul>
<li><p>You are locked into their ecosystem, as there is no standard library compatibility.</p>
</li>
<li><p>Too much magic involved to gain speed that no one will ever notice.</p>
</li>
<li><p>To get the full benefits, you will be forced to write in an unidiomatic and advanced style of Go.</p>
</li>
</ul>
<h2 id="heading-summary-tldr">Summary (TL;DR)</h2>
<p>Go has a comprehensive standard library that takes care of <em>almost</em> everything necessary for the vast majority of web applications. If you have a choice, it is unnecessary to use a framework just to build an API service.</p>
]]></content:encoded></item><item><title><![CDATA[Why Angular is perfect for web development]]></title><description><![CDATA[It isn’t.]]></description><link>https://blog.zackryrosli.com/why-angular-is-perfect-for-web-development</link><guid isPermaLink="true">https://blog.zackryrosli.com/why-angular-is-perfect-for-web-development</guid><dc:creator><![CDATA[Zack]]></dc:creator><pubDate>Wed, 13 Mar 2024 09:35:26 GMT</pubDate><content:encoded><![CDATA[<p>It isn’t.</p>
]]></content:encoded></item></channel></rss>