<?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[satria.technology]]></title><description><![CDATA[satria.technology]]></description><link>https://satria.technology</link><generator>RSS for Node</generator><lastBuildDate>Thu, 09 Apr 2026 09:56:51 GMT</lastBuildDate><atom:link href="https://satria.technology/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Rediscovering Concurrency in Go]]></title><description><![CDATA[When I first encountered Go, the discussions around goroutines and channels were overwhelming. As a computer science graduate, I was familiar with threads, but I didn't anticipate the unique approach Go offers.
My experience with a talking doll proje...]]></description><link>https://satria.technology/rediscovering-concurrency-in-go</link><guid isPermaLink="true">https://satria.technology/rediscovering-concurrency-in-go</guid><category><![CDATA[Go Language]]></category><category><![CDATA[concurrency]]></category><category><![CDATA[C]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Sun, 03 Aug 2025 08:39:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754209891066/de6e4608-fe43-44d6-a3df-21f3e853e7c8.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I first encountered Go, the discussions around goroutines and channels were overwhelming. As a computer science graduate, I was familiar with threads, but I didn't anticipate the unique approach Go offers.</p>
<p>My experience with a talking doll project coded in C highlighted the complexities of managing multiple inputs and outputs using raw threads. This experience underscored the absence of Go's streamlined concurrency features, such as channels and lightweight goroutines.</p>
<p>This article aims to bridge the gap left by many Go tutorials by delving into the fundamentals of concurrency, comparing Go's approach with the more manual methods in C.</p>
<h1 id="heading-what-is-concurrency">What is concurrency?</h1>
<p>You may need to know <strong>parallelism</strong> as well, this will make us easier to understand the concept!</p>
<p><strong>Concurrency</strong> means structuring our program to handle multiple tasks at once, but not necessarily doing them at the same time. People like to use this kitchen analogy. Imagine you are cooking a dish. You need to do several things and switching between: start boiling water, meanwhile you can chopping onions, then get back to the boiling water. When you only have one CPU core, concurrency is an illusion of multitasking which basically it is not! It’s about managing lot of things and not doing all of them at once.</p>
<p><strong>Parallelism</strong> means doing multiple things at the same time. Let’s get back to the kitchen analogy. Now you have a cook helper that can help you chopping onions while you are boiling water. Both of you doing multiple things at the exact same time simultaneously. You need to have multiple CPU core to do this. It’s about execution, not structuring.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754102585819/1220ff7a-fbcc-479a-85d6-133c597b1d73.png" alt class="image--center mx-auto" /></p>
<p>When implementing concurrency, sometime we don’t care how the computer is executing things. Theses tasks could be run in single core or might be run in multiple core, the programming language is helping us to structure the process to make it look like run simultaneously.</p>
<h1 id="heading-concurrency-in-your-language">Concurrency in Your Language</h1>
<p>Many programming language have different way to implement concurrency. We are focusing on C and Go.</p>
<p>I think, Go’s concurrency it is easy to understand. However if we don’t understand how it is in C, we will not appreciate the luxury we have in Go. When I worked with C threads, every mistake was painful. Race conditions is first class concern, deadlock is your friend, anything you named it.</p>
<p>Go gives a safer tool to implement concurrency, but the core problems don’t disappear. Do you familiar with these: nil pointer panic, resource lock, deadlock, etc.</p>
<p>We still need to grasp the fundamentals, I think C is the best way to start.</p>
<h1 id="heading-how-to-re-learn-concurrency-may-includes-un-learn">How to re learn concurrency (may includes un learn)</h1>
<ol>
<li><h2 id="heading-learn-basic-of-concurrency-in-go">Learn basic of concurrency in Go</h2>
</li>
</ol>
<p>Let’s stop pretending you have unlimited time. If you need to get code running—<em>now</em>—Go’s concurrency model is the shortest path between problem and solution. Here’s the bare minimum to get started:</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">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">processTask</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
    fmt.Printf(<span class="hljs-string">"Task %d starting\n"</span>, id)
    time.Sleep(<span class="hljs-number">1</span> * time.Second) <span class="hljs-comment">// Simulate long running process</span>
    fmt.Printf(<span class="hljs-string">"Task %d done\n"</span>, id)
    <span class="hljs-keyword">return</span> id * 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">for</span> i := <span class="hljs-number">1</span>; i &lt;= <span class="hljs-number">3</span>; i++ {
        <span class="hljs-keyword">go</span> processTask(i)
    }
    time.Sleep(<span class="hljs-number">2</span> * time.Second) <span class="hljs-comment">// Wait for tasks to finish (not production-safe, but fine for demo)</span>
    fmt.Println(<span class="hljs-string">"All tasks launched."</span>)
}
</code></pre>
<p>See it by yourself, no explanation needed at this point.</p>
<ol start="2">
<li><h2 id="heading-recognize-several-concurrency-patterns">Recognize several concurrency patterns.</h2>
</li>
</ol>
<p>Let’s start listing popular concurrency pattern in Go, here are the patterns every junior should know without excuse. These patterns introduce <strong>correct</strong> and <strong>maintainable</strong> concurrent code, which save your life in the long run.</p>
<h3 id="heading-pattern-1-fan-out-fan-in">pattern 1: Fan out / fan in</h3>
<p><strong>When to use:</strong> You have a bunch of work and want to split it among workers, then collect the results.</p>
<p>You are processing multiple things at once. Try experimenting processing things only using single loop, do you spot the different. Is it faster?</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">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">processTask</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
    fmt.Printf(<span class="hljs-string">"Task %d starting\n"</span>, id)
    time.Sleep(<span class="hljs-number">1</span> * time.Second) <span class="hljs-comment">// Simulate long running process</span>
    fmt.Printf(<span class="hljs-string">"Task %d done\n"</span>, id)
    <span class="hljs-keyword">return</span> id * id
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">worker</span><span class="hljs-params">(jobs &lt;-<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>, results <span class="hljs-keyword">chan</span>&lt;- <span class="hljs-keyword">int</span>)</span></span> {
    <span class="hljs-keyword">for</span> job := <span class="hljs-keyword">range</span> job
        results &lt;- processTask(job)
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    numJobs := <span class="hljs-number">10</span>
    numWorkers := <span class="hljs-number">3</span>
    jobs := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>, numJobs)
    results := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>, numJobs)

    <span class="hljs-comment">// Send jobs</span>
    <span class="hljs-keyword">for</span> j := <span class="hljs-number">1</span>; j &lt;= numJobs; j++ {
        fmt.Printf(<span class="hljs-string">"Sending job %d\n"</span>, j)
        jobs &lt;- j
    }
    <span class="hljs-built_in">close</span>(jobs) <span class="hljs-comment">// Close the jobs channel to signal no more jobs will be sent</span>

    <span class="hljs-comment">// Fan-out: launch multiple workers</span>
    <span class="hljs-keyword">for</span> w := <span class="hljs-number">1</span>; w &lt;= numWorkers; w++ {
        <span class="hljs-keyword">go</span> worker(jobs, results)
    }

    <span class="hljs-comment">// Fan-in: collect results</span>
    <span class="hljs-keyword">for</span> a := <span class="hljs-number">1</span>; a &lt;= numJobs; a++ {
        res := &lt;-results
        fmt.Printf(<span class="hljs-string">"Result received: %d\n"</span>, res)
    }
}
</code></pre>
<h3 id="heading-pattern-2-pipeline">pattern 2: Pipeline</h3>
<p><strong>When to use:</strong> Data needs to be processed in stages (think: factory line).</p>
<p>You can actually spawn multiple identical or different worker per stage, while they still meeting to the same stage. I have never use this on my usecase however.</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">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">processTask</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
    fmt.Printf(<span class="hljs-string">"Task %d starting\n"</span>, id)
    time.Sleep(<span class="hljs-number">1</span> * time.Second) <span class="hljs-comment">// Simulate long running process</span>
    fmt.Printf(<span class="hljs-string">"Task %d done\n"</span>, id)
    <span class="hljs-keyword">return</span> id * id
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">processTaskAdvanced</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
    fmt.Printf(<span class="hljs-string">"Advanced Task %d starting\n"</span>, id)
    time.Sleep(<span class="hljs-number">1</span> * time.Second) <span class="hljs-comment">// Simulate longer process</span>
    fmt.Printf(<span class="hljs-string">"Advanced Task %d done\n"</span>, id)
    <span class="hljs-keyword">return</span> id * id * <span class="hljs-number">2</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">workerStage1</span><span class="hljs-params">(jobs &lt;-<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>, results <span class="hljs-keyword">chan</span>&lt;- <span class="hljs-keyword">int</span>)</span></span> {
    <span class="hljs-keyword">for</span> job := <span class="hljs-keyword">range</span> jobs {
        results &lt;- processTask(job)
    }
    <span class="hljs-built_in">close</span>(results)
    fmt.Println(<span class="hljs-string">"Stage 1 processing complete"</span>)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">workerStage2</span><span class="hljs-params">(jobs &lt;-<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>, results <span class="hljs-keyword">chan</span>&lt;- <span class="hljs-keyword">int</span>)</span></span> {
    <span class="hljs-keyword">for</span> job := <span class="hljs-keyword">range</span> jobs {
        results &lt;- processTaskAdvanced(job)
    }
    <span class="hljs-built_in">close</span>(results)
    fmt.Println(<span class="hljs-string">"Stage 2 processing complete"</span>)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    jobs := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>, <span class="hljs-number">10</span>)
    <span class="hljs-comment">// Send jobs</span>
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">1</span>; i &lt;= <span class="hljs-number">10</span>; i++ {
        jobs &lt;- i
    }
    <span class="hljs-built_in">close</span>(jobs) <span class="hljs-comment">// Close the jobs channel to signal no more jobs will be sent</span>

    <span class="hljs-comment">// Single worker for stage 1</span>
    stage1 := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>)
    <span class="hljs-keyword">go</span> workerStage1(jobs, stage1)

    <span class="hljs-comment">// Single worker for stage 2</span>
    stage2 := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>)
    <span class="hljs-keyword">go</span> workerStage2(stage1, stage2)

    <span class="hljs-comment">// Collect results from stage 2</span>
    <span class="hljs-keyword">for</span> result := <span class="hljs-keyword">range</span> stage2 {
        fmt.Println(<span class="hljs-string">"Result:"</span>, result)
    }
}
</code></pre>
<h3 id="heading-pattern-3-worker-pool">pattern 3: Worker Pool</h3>
<p><strong>When to use:</strong> You need to control concurrency—don’t spawn a million goroutines and pray.</p>
<p>When you encounter random slowdowns, you can still process the other by spawning multiple worker.</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">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">processTask</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">int</span></span> {
    fmt.Printf(<span class="hljs-string">"Task %d starting\n"</span>, id)
    time.Sleep(<span class="hljs-number">1</span> * time.Second) <span class="hljs-comment">// Simulate long running process</span>
    fmt.Printf(<span class="hljs-string">"Task %d done\n"</span>, id)
    <span class="hljs-keyword">return</span> id * id
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">worker</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>, jobs &lt;-<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>, results <span class="hljs-keyword">chan</span>&lt;- <span class="hljs-keyword">int</span>)</span></span> {
    <span class="hljs-keyword">for</span> j := <span class="hljs-keyword">range</span> jobs {
        fmt.Printf(<span class="hljs-string">"worker %d started job %d\n"</span>, id, j)
        results &lt;- processTask(j)
        fmt.Printf(<span class="hljs-string">"worker %d finished job %d\n"</span>, id, j)
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    jobs := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>, <span class="hljs-number">100</span>)
    results := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>, <span class="hljs-number">100</span>)

    <span class="hljs-comment">// Start 3 workers</span>
    <span class="hljs-keyword">for</span> w := <span class="hljs-number">1</span>; w &lt;= <span class="hljs-number">3</span>; w++ {
        <span class="hljs-keyword">go</span> worker(w, jobs, results)
    }

    <span class="hljs-comment">// Send 5 jobs</span>
    <span class="hljs-keyword">for</span> j := <span class="hljs-number">1</span>; j &lt;= <span class="hljs-number">5</span>; j++ {
        jobs &lt;- j
    }
    <span class="hljs-built_in">close</span>(jobs)

    <span class="hljs-comment">// Collect results</span>
    <span class="hljs-keyword">for</span> a := <span class="hljs-number">1</span>; a &lt;= <span class="hljs-number">5</span>; a++ {
        res := &lt;-results
        fmt.Println(<span class="hljs-string">"result:"</span>, res)
    }
}
</code></pre>
<h3 id="heading-pattern-4-select-statement">pattern 4: Select Statement</h3>
<p><strong>When to use:</strong> You need to multiplex—wait for multiple things at once.</p>
<p>Try running the program. Observe that the program is receiving from both channels without blocking one another.</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">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    ch1 := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">string</span>)
    ch2 := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">string</span>)

    <span class="hljs-comment">// Goroutine 1</span>
    <span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
        time.Sleep(<span class="hljs-number">1</span> * time.Second)
        ch1 &lt;- <span class="hljs-string">"message from ch1"</span>
    }()

    <span class="hljs-comment">// Goroutine 2</span>
    <span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
        time.Sleep(<span class="hljs-number">2</span> * time.Second)
        ch2 &lt;- <span class="hljs-string">"message from ch2"</span>
    }()

    <span class="hljs-comment">// Using select to handle multiple channels</span>
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">2</span>; i++ { <span class="hljs-comment">// 2 since we expect two messages from both channels</span>
        <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> msg1 := &lt;-ch1:
            fmt.Println(<span class="hljs-string">"Received:"</span>, msg1)
        <span class="hljs-keyword">case</span> msg2 := &lt;-ch2:
            fmt.Println(<span class="hljs-string">"Received:"</span>, msg2)
        }
    }
}
</code></pre>
<h3 id="heading-pattern-5-waitgroup">pattern 5: WaitGroup</h3>
<p><strong>When to use:</strong> You need to wait for a bunch of goroutines to finish before moving on.</p>
<p>Observe the goutput order may vary due to goroutine scheduling.</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-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-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">5</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">(n <span class="hljs-keyword">int</span>)</span></span> {
            <span class="hljs-keyword">defer</span> wg.Done()
            time.Sleep(time.Second) <span class="hljs-comment">// Simulate work</span>
            fmt.Println(<span class="hljs-string">"Hello from goroutine"</span>, n)
        }(i)
    }
    wg.Wait() <span class="hljs-comment">// Block until all goroutines call Done()</span>
}
</code></pre>
<h3 id="heading-pattern-6-mutex">pattern 6: Mutex</h3>
<p><strong>When to use:</strong> You need to protect shared state—because goroutines WILL stomp on each other if you don’t.</p>
<p>Observe the output of the program to see how the counter is incremented by different goroutines.</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-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-keyword">var</span> mu sync.Mutex
    counter := <span class="hljs-number">0</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">(n <span class="hljs-keyword">int</span>)</span></span> {
            <span class="hljs-keyword">defer</span> wg.Done()

            <span class="hljs-comment">// Simulate some work</span>
            mu.Lock()
            counter++
            fmt.Printf(<span class="hljs-string">"Counter at goroutine %d: %d\n"</span>, n, counter)
            mu.Unlock()

        }(i)
    }

    wg.Wait()
}

<span class="hljs-comment">// Output:</span>
<span class="hljs-comment">// % go run main.go</span>
<span class="hljs-comment">// Counter at goroutine 9: 1</span>
<span class="hljs-comment">// Counter at goroutine 4: 2</span>
<span class="hljs-comment">// Counter at goroutine 0: 3</span>
<span class="hljs-comment">// Counter at goroutine 1: 4</span>
<span class="hljs-comment">// Counter at goroutine 2: 5</span>
<span class="hljs-comment">// Counter at goroutine 3: 6</span>
<span class="hljs-comment">// Counter at goroutine 7: 7</span>
<span class="hljs-comment">// Counter at goroutine 8: 8</span>
<span class="hljs-comment">// Counter at goroutine 5: 9</span>
<span class="hljs-comment">// Counter at goroutine 6: 10</span>
</code></pre>
<ol start="3">
<li><h2 id="heading-understand-what-goroutine-and-channel-is">Understand what goroutine and channel is</h2>
</li>
</ol>
<p>Before you copy-paste another “concurrent Go example,” stop and ask yourself these two questions:</p>
<h3 id="heading-question-1-how-many-tasks-do-you-actually-need">question 1: How many tasks do you actually need?</h3>
<p>If you just want to run something in parallel, use a goroutine.</p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> doSomething()
</code></pre>
<p>That’s it. No threads, no memory management, no boilerplate.</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;pthread.h&gt;</span></span>

<span class="hljs-function"><span class="hljs-keyword">void</span>* <span class="hljs-title">doSomething</span><span class="hljs-params">(<span class="hljs-keyword">void</span>* arg)</span> </span>{ <span class="hljs-comment">/* ... */</span> <span class="hljs-keyword">return</span> <span class="hljs-literal">NULL</span>; }
<span class="hljs-keyword">pthread_t</span> tid;
pthread_create(&amp;tid, <span class="hljs-literal">NULL</span>, doSomething, <span class="hljs-literal">NULL</span>);
pthread_join(tid, <span class="hljs-literal">NULL</span>);
</code></pre>
<p>In C, you have to create a thread, pass a function pointer, manage the result, then join. Every single time. If you forget to join, you leak resources. If you pass the wrong pointer, you get undefined behavior. Go’s goroutine is a single keyword.</p>
<h3 id="heading-question-2-how-do-you-pass-data-between-tasks"><strong>question 2:</strong> How do you pass data between tasks?</h3>
<p>If your goroutines need to talk to each other, you need a channel.</p>
<pre><code class="lang-go">ch := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">int</span>)
<span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
    ch &lt;- <span class="hljs-number">42</span> <span class="hljs-comment">// send data</span>
}()
fmt.Println(&lt;-ch) <span class="hljs-comment">// receive data</span>
</code></pre>
<p>Direct, safe, and built-in. No locks, no structs, no memory headaches.</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;pthread.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdlib.h&gt;</span></span>

<span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> {</span>
    <span class="hljs-keyword">int</span> value;
    <span class="hljs-keyword">pthread_mutex_t</span> lock;
} Data;

<span class="hljs-function"><span class="hljs-keyword">void</span>* <span class="hljs-title">worker</span><span class="hljs-params">(<span class="hljs-keyword">void</span>* arg)</span> </span>{
    Data* d = (Data*)arg;
    pthread_mutex_lock(&amp;d-&gt;lock);
    d-&gt;value = <span class="hljs-number">42</span>;
    pthread_mutex_unlock(&amp;d-&gt;lock);
    <span class="hljs-keyword">return</span> <span class="hljs-literal">NULL</span>;
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{
    Data d;
    d.value = <span class="hljs-number">0</span>;
    pthread_mutex_init(&amp;d.lock, <span class="hljs-literal">NULL</span>);

    <span class="hljs-keyword">pthread_t</span> tid;
    pthread_create(&amp;tid, <span class="hljs-literal">NULL</span>, worker, &amp;d);
    pthread_join(tid, <span class="hljs-literal">NULL</span>);

    pthread_mutex_lock(&amp;d.lock);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%d\n"</span>, d.value);
    pthread_mutex_unlock(&amp;d.lock);

    pthread_mutex_destroy(&amp;d.lock);
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>That’s so many lines of setup just to pass one integer. Miss a lock, your value is garbage. Miss a destroy call, you leak memory. Channel exists so you don’t have to write this anymore.</p>
<h3 id="heading-why-does-this-matter">Why does this matter?</h3>
<p>In Go, you focus on the problem that matter to you. It help you to ignore problem in concurrency, make it possible for you to ship fast.</p>
<h3 id="heading-remember-the-problem-is-still-there">Remember, the problem is still there</h3>
<p>You think just because you’re using Go, all your concurrency problems vanish? Wrong. ere’s a classic mistake: leaking goroutines and memory.</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">"time"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">leakyWorker</span><span class="hljs-params">(done <span class="hljs-keyword">chan</span> <span class="hljs-keyword">bool</span>)</span></span> {
    <span class="hljs-keyword">for</span> {
        <span class="hljs-keyword">select</span> {
        <span class="hljs-keyword">case</span> &lt;-done:
            fmt.Println(<span class="hljs-string">"Worker stopped"</span>)
            <span class="hljs-keyword">return</span>
        <span class="hljs-keyword">default</span>:
            <span class="hljs-comment">// Simulate work, but never actually receive "done"</span>
            time.Sleep(<span class="hljs-number">100</span> * time.Millisecond)
        }
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    done := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">bool</span>)

    <span class="hljs-comment">// Start 5 workers, but never signal them to stop</span>
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">5</span>; i++ {
        <span class="hljs-keyword">go</span> leakyWorker(done)
    }

    fmt.Println(<span class="hljs-string">"Main finished, but workers are still running and eating memory..."</span>)
    time.Sleep(<span class="hljs-number">5</span> * time.Second)
}
</code></pre>
<p>What’s wrong here?</p>
<ul>
<li><p>Go routine is started, but never stopped.</p>
</li>
<li><p><code>done</code> channel is never closed or signaled.</p>
</li>
<li><p>Worker is looping forever, eating RAM and CPU.</p>
</li>
</ul>
<p>Imagine doing inside HTTP handlers or message consumer. You will kill your server eventually.</p>
<p>Go is safe, but it’s not idiot-proof. It’s just tiring to see this issue in production.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754102155083/094405e1-ae09-42f0-aa3e-133ed27a6745.png" alt class="image--center mx-auto" /></p>
<ol start="4">
<li><h2 id="heading-lets-normalize-it-depends-statement">Let’s normalize “it depends” statement</h2>
</li>
</ol>
<p>If you are looking for a silver bullet, you are wasting your time. How many time do I witness overusing concurrency without meaningful goal, just making the code hard to read and maintain!</p>
<p><strong>“It depends”</strong>, is not a lazy answer. It’s the only honest answer in real life.</p>
<p>Don’t just follow a blog post that uses channels everywhere. They are just a blog post after all.</p>
<p>Analyze the context, what’s the problem you are trying to solve? Ask your favorite AI to deep dive into the problem, start comparing multiple solutions.</p>
<p>Now that you see different solutions, validate both the problem solving and the implementation. Is it satisfying the requirement? Is it safe to run in production?</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this era, people easily forget the fundamentals. AI spits out code, people just straight to “tab tab tab and push”. When you don’t know a thing, you are just a monkey pushing buttons.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754102005762/a3bccc64-552b-4020-8a7f-7361e2edb994.png" alt class="image--center mx-auto" /></p>
<p><strong>Real engineer review fundamentals</strong>. Want to design a solid architecture? Start learning system design. Want to write a solid concurrent Go code? See underneath it, how concurrency really works in C. If you never fought with threads, locks, and memory leaks in C, you will not appreciate the power Go gives you.</p>
<p><strong>Stop being a code monkey.</strong> Before you hit accept, read carefully. Test it, break it, fix it. You are senior reviewing your junior AI robot’s work. If you don’t catch the bugs, nobody will.</p>
<p>Respect the fundamentals. Use the tools, don’t let them use you. If you are really a senior, act like it.</p>
]]></content:encoded></item><item><title><![CDATA[Tracking Your Productivity as a Software Engineer, start from yourself]]></title><description><![CDATA[Have you ever considered checking how productive you are as a software engineer? You might think, "Why bother, especially if the company doesn't track it?" But, by looking at productivity metrics, you can understand your value, what you bring to the ...]]></description><link>https://satria.technology/tracking-your-productivity-as-a-software-engineer-start-from-yourself</link><guid isPermaLink="true">https://satria.technology/tracking-your-productivity-as-a-software-engineer-start-from-yourself</guid><category><![CDATA[Productivity]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Wed, 23 Apr 2025 16:55:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745427255177/e85e8826-ae18-43bb-94b2-f7e41337adf1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever considered checking how productive you are as a software engineer? You might think, "Why bother, especially if the company doesn't track it?" But, by looking at productivity metrics, you can understand your value, what you bring to the company, and how you're growing as a professional.</p>
<h2 id="heading-having-a-goal-in-mind">Having a Goal in Mind</h2>
<p>While it's possible to start analyzing metrics immediately, it can be beneficial to begin with a personal goal. This goal can help you stay focused and motivated. Ask yourself what you aim to achieve - is it faster delivery, fewer bugs, or improved estimation?</p>
<h2 id="heading-start-with-popular-metrics">Start with Popular Metrics</h2>
<p>Get familiar with established metrics like something as follow:</p>
<ul>
<li><p><strong>DORA Metrics (Deployment Frequency, Lead Time for Changes, Change Failure Rate, Time to Restore Service):</strong> These offer insights into your team's and potentially your individual impact on delivery and stability.</p>
</li>
<li><p><strong>Cycle Time:</strong> How long it takes for your code contributions to go from start to deployment.</p>
</li>
<li><p><strong>Throughput:</strong> The number of tasks or stories you complete within a specific timeframe.</p>
</li>
<li><p><strong>Code Quality Metrics (e.g., bug count in your code):</strong> While harder to isolate individually, tracking bugs related to your changes can be insightful.</p>
</li>
</ul>
<h2 id="heading-getting-started">Getting Started</h2>
<p>Tracking key metrics can provide valuable insights to enhance your decision-making and optimize your workflow. Here's how to get started in two simple steps:</p>
<ul>
<li><p><strong>Automate Data Capture:</strong> Manual tracking is inefficient. Explore using local tools or scripts to automate the process. If your company permits, consider implementing data capture on company servers, ensuring secure access and the potential for sharing anonymized data with your team.</p>
</li>
<li><p><strong>Create a Visualization:</strong> Once you've collected data, visualize it to uncover trends and patterns. Even a basic spreadsheet with charts can effectively reveal insights that align with your objectives.</p>
</li>
</ul>
<h2 id="heading-how-do-you-actually-start">How do you actually start?</h2>
<p>Don't be discouraged by the lack of advanced tools. Begin with the data you can access. I started by analyzing my JIRA ticket history to measure my average cycle time and throughput. You could also track incidents directly caused by your code changes and measure your average time to recovery.</p>
<p>Take the initiative and act instead of waiting for others to do it for you.</p>
<h2 id="heading-lesson-learned">Lesson Learned</h2>
<p>While my manager doesn't require detailed productivity metrics, tracking my own has been incredibly beneficial. It helps me objectively evaluate my performance, pinpoint areas for improvement, and focus on professional development. This data-driven approach provides concrete evidence to support my self-assessments and career growth.</p>
<p>Tracking your productivity isn't about micromanagement; it's about self-awareness and empowerment. In the rapidly changing landscape of the Fourth Industrial Revolution, understanding your capabilities through data will make you a more disciplined and effective professional. It's an investment in your personal and professional growth.</p>
<p>I'd love to hear about your experiences with tracking your own productivity. What metrics have you found most valuable?</p>
]]></content:encoded></item><item><title><![CDATA[Kitchen Renovation: An Engineer's Insight Beyond Coding]]></title><description><![CDATA[You are a Software Engineer, with “engineer” in the back. Have you ever thought about what that word means? I spent the last month and a half working on a big project: kitchen extension in my new house!! Instead of giving it all to somebody, I manage...]]></description><link>https://satria.technology/kitchen-renovation-an-engineers-insight-beyond-coding</link><guid isPermaLink="true">https://satria.technology/kitchen-renovation-an-engineers-insight-beyond-coding</guid><category><![CDATA[project management]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Mon, 07 Apr 2025 01:50:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743990569147/0b7171b2-3f0f-4426-a0fe-c9f4dee3fa08.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You are a Software Engineer, with “engineer” in the back. Have you ever thought about what that word means? I spent the last month and a half working on a big project: kitchen extension in my new house!! Instead of giving it all to somebody, I managed it all myself and hired a senior constructor worker for a month. What I learned changed how I see being an “engineer”, it’s similar to what we do in software.</p>
<h1 id="heading-what-does-engineer-actually-mean">What does “engineer” actually mean?</h1>
<p>Writing code is just a small essence of software engineering, what it truly lies is in applying a systematic and disciplined approach to solve problems and create appropriate solutions.</p>
<ol>
<li><p><strong>Problem identification</strong><br /> Start by identifying the goal of the project. Usually, it comes as a problem statement and brief background.</p>
</li>
<li><p><strong>Research the background</strong><br /> Proactively research the problem given to you and possible solutions from similar problems.</p>
</li>
<li><p><strong>Requirement specification</strong><br /> Prioritize and list the most important point for the project, one project with another will be different even if it is similar.</p>
</li>
<li><p><strong>Brainstorm the solution</strong><br /> Think of all the alternatives. Don’t just focus on one solution, a risk overlooking a better solution.</p>
</li>
<li><p><strong>Develop the solution</strong><br /> Communicate the solution properly to the executor. Have proper control to be able to meet the plan.</p>
</li>
<li><p><strong>Test and revise</strong><br /> Be ready to revise your solution once it has been developed. In some cases, you don’t have the privilege anymore to restart everything from point zero.</p>
</li>
<li><p><strong>Result communicated</strong><br /> Set up a demo, presentation, report, or display to others. Pretty sure, as a project owner, you are working on this project on behalf of someone else.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743914512146/f5f67522-9f76-452a-a0bf-9a7b88554e9f.png" alt="Universal project management process, each actor concern to some overlapping process." class="image--center mx-auto" /></p>
<h1 id="heading-my-kitchen-renovation-project-an-unexpected-engineering-masterclass">My Kitchen Renovation Project: an unexpected engineering masterclass</h1>
<p>As the project owner of my kitchen renovation, where I report directly to the stakeholder (my family: wife, kids), I found myself relying heavily on the very same principles I use daily as a software engineer:</p>
<ol>
<li><p><strong>Problem identification</strong><br /> My family and I meticulously thought about our needs for the new kitchen space. We also discussed some of the characteristics like the flow of usage, aesthetic, budget, and deadline.</p>
</li>
<li><p><strong>Research the background</strong><br /> I personally spent hours on kitchen layout and design trends on pinterest, materials on local depository, kitchen appliances on shopee.</p>
</li>
<li><p><strong>Requirement specification</strong><br /> Since I could not copy paste what I have seen on pinterest, I began listing down some requirements that need to be finished given the problem we have set.</p>
</li>
<li><p><strong>Brainstorm the solution</strong><br /> Almost for every item, I come up with some alternatives. The layout for example, deciding on L shape or C shape comes with pros and cons. As well as choosing ceramic over granite, and others.</p>
</li>
<li><p><strong>Develop the solution</strong><br /> I hired one senior construction worker and a junior helping him. I communicate my plan in a language we all understand. They also gave feedback when my plan needed more effort or was uncommon, so we all can still achieve the project within the budget and deadline.</p>
</li>
<li><p><strong>Test and revise</strong><br /> No matter how perfect your design is, the execution could go wrong unexpectedly. That’s when you need to revise your design and come up with another solution.</p>
</li>
<li><p><strong>Result communicated</strong><br /> For my case, I invite my family over about weekly or biweekly to check the progress. I presented the progress we have reached so far.</p>
</li>
</ol>
<h1 id="heading-the-universal-discipline-of-engineering">The Universal Discipline of Engineering</h1>
<p>My experience working on the kitchen extension project showed me that being an “engineer” is like having a special way to solve problems, any problems. It does not matter if you are writing code or building a kitchen ceiling: you still need to know the problem is, plan all the way, do the work, and finally check if it is right.</p>
<h1 id="heading-shaping-your-career-and-personal-growth">Shaping Your Career and Personal Growth</h1>
<p>Understanding this universal definition can be incredibly empowering you personally and most importantly your career!</p>
<ol>
<li><p><strong>Enhanced Problem Solving</strong><br /> You will have a structured thinking on identifying the problem, proposing the solution, up to work on it effectively.</p>
</li>
<li><p><strong>Improved Communication</strong><br /> The planning session will help you to articulate your thought process and invite a healthy discussion with all stakeholders. You also get a chance to collaborate with individuals from different backgrounds and different intentions, focusing on the shared language.</p>
</li>
<li><p><strong>Increased Adaptability</strong><br /> You will come to realize that a perfect plan will break eventually, by applying your engineering mindset for a dynamic situation makes you more versatile.</p>
</li>
<li><p><strong>Personal Empowerment</strong><br /> By recognizing your inherent problem solving, it boosts your confidence to tackle challenges beyond coding.</p>
</li>
</ol>
<h1 id="heading-conclusion">Conclusion</h1>
<p>The last kitchen extension project really showed something for me: I'm an engineer, not just a software engineer. Seeing how my problem-solving skills translated so well, and with my family happy with the result (and me too!), it inspired us for other future projects like building a kitchen cabinet, carport, and even handling electricity and AC installation.</p>
<p>Of course, as a professional Software Engineer, I need to carefully balance the time I dedicate to these personal projects with the crucial effort of honing my core software engineering skills. :(</p>
<p>Anyway! Have you ever found your “engineering brain” kicking in outside of your domain realm? Share your experiences in the comment below! What unexpected projects or situations have you approached?</p>
]]></content:encoded></item><item><title><![CDATA[Decoding 1:1 meeting: Guidance and Theory]]></title><description><![CDATA[I remember the very first time I had this meeting. My manager suddenly invited me to a strange meeting named, “Satria / Alana”, the invitee was only me and him. I felt anxious about what would happen, did I in trouble? The description did not help, i...]]></description><link>https://satria.technology/decoding-11-meeting-guidance-and-theory</link><guid isPermaLink="true">https://satria.technology/decoding-11-meeting-guidance-and-theory</guid><category><![CDATA[Software Engineering]]></category><category><![CDATA[Career]]></category><category><![CDATA[Productivity]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Tue, 28 Jan 2025 02:00:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737987568103/5288f9f5-f482-4e53-ab90-0a627340b0d2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I remember the very first time I had this meeting. My manager suddenly invited me to a strange meeting named, “Satria / Alana”, the invitee was only me and him. I felt anxious about what would happen, did I in trouble? The description did not help, it was to discuss my annual performance and feedback.</p>
<p>Later, I learned that one-on-one meetings are not an annual event to discuss my employees' performance only. As a Tech Lead, I schedule biweekly 1:1 meetings with all my team members. Of course, I also regularly have 1:1 meetings with my manager.</p>
<p>I have come to appreciate just how valuable this meeting can be for everyone, including the company. In this article, I will tell you <strong>What is 1:1 meeting? What could you expect? How do you benefit from it?</strong></p>
<h2 id="heading-what-is-11-one-on-one-meeting">What is 1:1 (one on one) meeting?</h2>
<p>I will take the definition from “The Effective Manager” by Mark Horstman</p>
<p><em>A regularly scheduled meeting between a manager and each of their direct reports to discuss anything the direct wants to discuss.</em></p>
<p>Let’s take a key takeaway from it:</p>
<ol>
<li><p><strong>Regularity</strong> is crucial, consistent is the key</p>
</li>
<li><p><strong>Focus individually</strong> personally, that’s why there is only you and your manager</p>
</li>
<li><p><strong>Owned by a direct report</strong>, not the manager. We own the agenda, not our manager.</p>
</li>
</ol>
<p>Another definition also comes up from my favorite book “The Manager’s Path” by Camile Fournier</p>
<p><em>An essential feature of good working relationship</em></p>
<p>She explains the reason of why 1:1 exists:</p>
<ol>
<li><p>To create a <strong>human connection</strong> between us and our manager</p>
</li>
<li><p>To create a <strong>regular</strong> opportunity for us to <strong>speak privately</strong> with our manager about whatever needs discussing.</p>
</li>
</ol>
<h2 id="heading-what-you-should-expect">What you should expect</h2>
<p>Typical 1:1 sessions may vary, depending on your needs and the culture of organization. Commonly, people use it for status updates, or to dive deep into ongoing or recent projects, although I prefer to avoid this scenario if we already have daily update meetings.</p>
<p>Worst case scenario, you never had 1:1 session with your manager except twice a year talking about the regular performance review cycle. I highly avoid this kind of situation, since you don’t prefer your feedback to be given only on performance review, it's too late.</p>
<p>There are some agenda that you may consider bringing up in your next 1:1 with your manager:</p>
<h3 id="heading-1-feedback"><strong>1. Feedback</strong></h3>
<p>In this scenario, you can bring up the recent project. Directly, ask him about things you could improve, then he will gladly give you the feedback or deliver the feedback collected from others. Focus on the correct way of doing it, although not every theory is practical.</p>
<h3 id="heading-2-guidance"><strong>2. Guidance</strong></h3>
<p>Quite similar to when you receive feedback, here you focus on the guidance of how you should perform and behave in the company. Remember, not every theory is practical, that’s when you need practical guidance, “this is how we do it in this company”</p>
<h3 id="heading-3-career-development"><strong>3. Career Development</strong></h3>
<p>Another portion to talk about is making sure you still perform in your current role, at the same time you still strive for mastery to excel. This is very important, even if you are not ambitious to participate in the next promotion, life is quite boring when you haven’t had a challenge. Ask for a project to stretch, so you can taste the unknown unknown to uncover your potential.</p>
<h3 id="heading-4-personal-matter"><strong>4. Personal matter</strong></h3>
<p>The small portion of the agenda you could bring up is to talk about personal matters and concern related to work. Sometimes, people bring up annual bonuses or changes in company policy. Do not expect your manager to know all the details, they probably as clueless as you, but rest assured that he will bring it up to higher-up management. If you want a job rotation to another product team, this is also where you can talk about it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737987174691/e292fe7b-fa4c-485d-898a-94856fc6f3f5.png" alt="A pie chart divided into four segments labeled: &quot;Professional Feedback,&quot; &quot;Career Development,&quot; &quot;Personal Matter,&quot; and &quot;Working Guidance.&quot;" class="image--center mx-auto" /></p>
<h2 id="heading-how-to-prepare">How to prepare</h2>
<h3 id="heading-1-come-up-with-your-agenda"><strong>1. Come up with your agenda</strong></h3>
<p>Remember that this is your agenda. Although, it is 100% ok for your manager if they come with his agenda. Just be sure you also had one.</p>
<p>Depending on the company culture, your manager is the one to schedule the meeting regularly. He always comes up with his agenda. This is usually happen when you are still junior, since you probably had no idea what to talk about.</p>
<p>Regardless of the situation, try to make a bullet point on what do you want to bring up. Refer to the some agenda I had mentioned earlier.</p>
<h3 id="heading-2-be-honest-and-open"><strong>2. Be honest and open</strong></h3>
<p>Be vulnerable, there is no point in defending your statement and behavior in this session. There is just no point. You need to receive as much as you can.</p>
<p>I had a friend who always had trouble with his manager. My friend had their own opinion on how things should work, which was not aligned with his manager. In this situation, the best way to come up is not to force the manager. Remember, “this is how we do it in this company” is all you need.</p>
<p>The thing is, you may need to deliver feedback to your manager. This is totally fine. Although you can not force your opinion on everyone, as a professional who sees flaws in the company, you need to raise that right away and come up with a possible solution.</p>
<h3 id="heading-3-take-notes-and-actionable-items"><strong>3. Take notes and actionable items</strong></h3>
<p>Walk the talk. Don’t let your valuable to go waste. Take a note and come up with an action item.</p>
<p>Too lazy on taking a note, invite AI note taker that you can integrate into Google Meeting. There are plenty options available. Even if you had the session offline in the office.</p>
<p>You probably do not to do active note-taking. During the meeting, you may need to focus on the talk and take one or two keywords for you to develop later on. Remember, you still need to create a human connection with your manager.</p>
<h2 id="heading-typical-11-session-run-down">Typical 1:1 Session Run Down</h2>
<p>For you who had not had a 1:1 meeting session before, I will give you a reference on what the session look like.</p>
<ul>
<li><p><strong>00:00 - 00:05 → small chit chat</strong><br />  Get to know personally. Bring up a light topic like “how did you get home yesterday?”, “Had you catch a rain on the way home?”, “The meeting with the product yesterday was quite awful, we could do better, bla bla bla.”</p>
</li>
<li><p><strong>00:06 - 00:35 → your main agenda</strong>, about 1 or 2 things<br />  Bring a recent event to the table, ask your manager on how you could be better with it. Ask for feedback or guidance. (refer to previous section)</p>
</li>
<li><p><strong>00:36 - 00:45 → additional agenda</strong><br />  Spare some time for your manager’s agenda, you never want to miss what they want to talk to you.</p>
</li>
<li><p><strong>00:46 - 01:00 → buffer time</strong><br />  Use it if you have to</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737987182099/dc5044d0-80c6-4fc9-b7a4-76f4a1d176d3.png" alt="A diagram showing a meeting session divided into four 15-minute sections: &quot;warm up,&quot; &quot;main agenda,&quot; &quot;additional agenda,&quot; and &quot;buffer,&quot; each in different colors." class="image--center mx-auto" /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Just like everybody else, I had mistaken what 1:1 for a regular performance review cycle and status update. I missed the opportunity to create connection and growth. The misconception is common, and that’s why not everybody agrees with this concept.</p>
<p>Even now, I still face difficulty on maintaining my 1:1, with my team members and my manager. While it is easy for me to control the agenda for my manager, I have consciously tended to update the latest and ongoing projects. Toward my direct reports, while it is easy for me to leave the agenda to them, I tend to preach for a solid 1 hour without ever actively listening to their story and concerns.</p>
<p>Afterall, for sure I had the best professional connection in my career once I had my regular 1:1 session.</p>
<p>What is your experience with 1:1 meetings? Do you have them regularly, if not what stopping you? Let’s learn from each other.</p>
<hr />
<p>References:</p>
<ul>
<li>Fournier, C. (2017). <em>The manager’s path: A Guide for Tech Leaders Navigating Growth and Change</em>.</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Beyond Layers: Choosing The Right Architecture for Complex Problem]]></title><description><![CDATA[You were not hired to solve trivial problems. You were hired to tackle the complex, the secret sauce that makes your company great! That’s why they need you – to translate their core business logic into robust, efficient, scalable software.
Yet, many...]]></description><link>https://satria.technology/beyond-layers-choosing-the-right-architecture-for-complex-problem</link><guid isPermaLink="true">https://satria.technology/beyond-layers-choosing-the-right-architecture-for-complex-problem</guid><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Sun, 12 Jan 2025 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736933658533/84351791-06b6-4451-851d-dc610277d35c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You were not hired to solve trivial problems. You were hired to tackle the complex, the secret sauce that makes your company great! That’s why they need you – to translate their core business logic into robust, efficient, scalable software.</p>
<p>Yet, many still default to them. This is a dangerous game. So trying out an idea with a simple MVP project should not be in your hand. “Premature Optimization Is the Root of All Evil”, indeed, but underestimating the problem is a guaranteed path to disaster.</p>
<p>If you are reading this, it is because you understand this fundamental truth: complex problems require well considered architectures. You are here to find the right one, and I commend you for it 👍</p>
<h2 id="heading-some-architectural-patterns">Some Architectural Patterns</h2>
<p>Choosing the right architecture needs a deep understanding of your project requirements. Once you have a clear understanding, you can explore suitable architectural patterns. Here are some common architectures.</p>
<h3 id="heading-layered-architecture">Layered Architecture</h3>
<p>Organize application into horizontal layers, each with specific technical responsibility (e.g. presentation, business, data access).</p>
<p>Suitable for simpler application with clear separation of concerns. Easy to understand and implement, but can become difficult to scale for complex systems.</p>
<h3 id="heading-service-oriented-architecture">Service Oriented Architecture</h3>
<p>A collection of services that communicate with each other with a central service bus. Note that it is not a microservice.</p>
<h3 id="heading-pipeline-architecture">Pipeline Architecture</h3>
<p>Process data through stages or filters, each performs specific transportation on the data. It consists of filters and transformers.</p>
<p>Suitable for applications that process data in sequential manner.</p>
<h3 id="heading-microkernel-architecture-plug-in-architecture">Microkernel Architecture (Plug-in Architecture)</h3>
<p>Consist of core system and optional microkernel (plug in module). This allows for extensibility and customization without modifying the core system. Think of web browser extensions.</p>
<p>Suitable for systems with high extensibility and customization.</p>
<h3 id="heading-event-driven-architecture">Event-Driven Architecture</h3>
<p>Focus on applying a particular process for a particular emitted event. When implementing, it can be challenging to debug and trace the flow.</p>
<p>Suitable for application with real time data processing, asynchronous communication, and complex event processing.</p>
<h3 id="heading-microservices-architecture">Microservices Architecture</h3>
<p>Decomposes the application into small and independent services that communicate with each other over the network. Each service has its own clear business justification.</p>
<p>Suitable for complex applications with high scalability, independent deployment, and diverse tech stacks.</p>
<h3 id="heading-orchestration-driven-architecture">Orchestration-Driven Architecture</h3>
<p>It involves a central orchestrator that coordinates the interaction between services. Not only do you need to maintain the process flow, but the running infrastructure as well.</p>
<p>Suitable for complex business processes that need to be coordinated all together through central command and monitoring.</p>
<h2 id="heading-practical-tips">Practical Tips</h2>
<p>Effectively navigating complex architectural challenges requires a structured approach. Here are some actionable tips to guide you:</p>
<h3 id="heading-1-deeply-understand-the-problem">1. Deeply Understand the Problem</h3>
<p>Don't rush into solutions before truly grasping the problem's nuances. Dedicate focused time to gather information. I find a focused session (like a Pomodoro) extremely valuable for this.</p>
<p>During this time, gather all available facts, evidence, and documentation. Critically verify incoming requirements and analyze the problem domain. Key aspects to consider include:</p>
<ul>
<li><p><strong>Background:</strong> What is the context of this problem? What are the business drivers behind it?</p>
</li>
<li><p><strong>Scope:</strong> What are the boundaries of the problem? What is included and excluded?</p>
</li>
<li><p><strong>Explicit and Implicit Requirements:</strong> What are the stated requirements, and what are the unspoken assumptions or implied needs?</p>
</li>
<li><p><strong>User Flows:</strong> How will users interact with the system? What are the typical user journeys?</p>
</li>
<li><p><strong>Data Schema:</strong> What data will the system handle? What are the relationships between different data elements?</p>
</li>
</ul>
<h3 id="heading-2-strategically-review-architectural-patterns">2. Strategically Review Architectural Patterns</h3>
<p>Familiarize yourself with common architectural patterns and their trade-offs. As mentioned earlier, common patterns offer different strengths and weaknesses. The goal is not to force-fit a pattern but to select the one that best aligns with the specific requirements of your problem. Remember: there's no silver bullet. Consider these factors:</p>
<ul>
<li><p><strong>Alignment with Requirements:</strong> Does the pattern address the key scalability, performance, security, and maintainability needs?</p>
</li>
<li><p><strong>Company Standards:</strong> Does the pattern align with existing company norms, standards, and infrastructure?</p>
</li>
<li><p><strong>Team Expertise:</strong> Does the team have the necessary skills and experience to implement and maintain the chosen pattern?</p>
</li>
</ul>
<h3 id="heading-3-validate-with-a-targeted-prototype">3. Validate with a Targeted Prototype</h3>
<p>Before committing to a full-scale implementation, build a small, focused prototype to validate key assumptions and identify potential roadblocks early. This allows you to experiment with different approaches and refine your design before investing significant development effort.</p>
<p>While AI assistants can be helpful for quick explorations and code generation, remember that a well-designed prototype should still be carefully planned and executed to provide meaningful insights. Focus on these aspects:</p>
<ul>
<li><p><strong>Key Functionality:</strong> Focus on implementing the core features that are most critical to validate the architectural choices.</p>
</li>
<li><p><strong>Performance Testing (if applicable):</strong> If performance is a critical concern, include basic performance testing in the prototype.</p>
</li>
<li><p><strong>Feedback and Iteration:</strong> Use the prototype to gather feedback from stakeholders and iterate on the design as needed.</p>
</li>
</ul>
<h3 id="heading-4-conduct-regular-architectural-reviews">4. Conduct Regular Architectural Reviews</h3>
<p>Architectural reviews are essential throughout the project lifecycle, not just at the beginning. Regular reviews foster shared understanding within the team, identify potential issues early, and ensure that the architecture remains aligned with evolving requirements. These reviews should be:</p>
<ul>
<li><p><strong>Regular and Scheduled:</strong> Establish a regular cadence for reviews (e.g., bi-weekly or monthly).</p>
</li>
<li><p><strong>Well-Prepared:</strong> Come prepared with specific topics to discuss and any relevant documentation.</p>
</li>
<li><p><strong>Documented:</strong> Use tools like Architecture Decision Records (ADRs) to document architectural decisions, their rationale, and any alternatives considered. This creates a valuable historical record and facilitates future discussions.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The practical tips outlined above—understanding the problem, reviewing architectural patterns, prototyping, and conducting reviews—are valuable in various scenarios: starting a new project, integrating with existing systems, adding complex features, or pursuing overall system improvements. However, simply knowing these steps isn't enough. The effectiveness of each step is crucial. This begs some important questions:</p>
<ul>
<li><p>How do you truly understand a complex problem? What techniques do you use to gather requirements and analyze the problem domain?</p>
</li>
<li><p>How do you efficiently identify relevant architectural patterns? Do you have a systematic approach to evaluating trade-offs and selecting the best fit?</p>
</li>
<li><p>How do you create a compelling and informative prototype that effectively communicates your architectural vision?</p>
</li>
<li><p>How do you clearly and persuasively communicate your architectural decisions to stakeholders, ensuring buy-in and shared understanding?</p>
</li>
</ul>
<p>If you're still with me, it's because you recognize that mastering these skills is an ongoing journey. Our discipline has developed countless frameworks, methodologies, and tools to enhance our effectiveness at each of these stages. From domain-driven design and use case analysis to architectural decision records (ADRs) and various prototyping techniques, there's a wealth of knowledge available. The danger lies in "wandering around," reinventing the wheel, and not leveraging these existing resources.</p>
<p>This moment is an opportunity for reflection: to acknowledge the vast landscape of knowledge that you may not yet have fully explored—the "unknown unknowns." Recognizing these gaps is the first step towards bridging them and becoming a more effective and impactful software architect.</p>
<p>Now it is your turn. Reflect on a complex problem you have faced and how you approved the architectural challenges. Above of all, what were the biggest lessons you learned? Share your experiences, insights, and even your mistakes in the comments below. Let’s learn from each other and collectively improve our architectural problem-solving skills.</p>
<hr />
<p>Ford, N., &amp; Richards, M. (2020). Fundamentals of software Architecture: An Engineering Approach. O’Reilly Media.</p>
<p>Khononov, V. (2021). Learning Domain-Driven design: Aligning Software Architecture and Business Strategy. O’Reilly Media.</p>
<p>The Guide to the Software Engineering Body of Knowledge (SWEBOK Guide)</p>
]]></content:encoded></item><item><title><![CDATA[Avoid This Simple Software Architectures for Solving Complex Problems]]></title><description><![CDATA[You’ve joined a company excited to tackle a project with complex software architecture. But as a junior developer, you soon realize how hard it is to learn, maintain, and scale. When new requirements arise, implementing them becomes cumbersome and er...]]></description><link>https://satria.technology/avoid-this-simple-software-architectures-for-solving-complex-problems</link><guid isPermaLink="true">https://satria.technology/avoid-this-simple-software-architectures-for-solving-complex-problems</guid><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Mon, 06 Jan 2025 02:36:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736137073140/cd2815a4-f00c-47e0-9c62-eb9d97d559c9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You’ve joined a company excited to tackle a project with complex software architecture. But as a junior developer, you soon realize how hard it is to learn, maintain, and scale. When new requirements arise, implementing them becomes cumbersome and error-prone. It’s easy to think that a simple architecture might be the solution, but simplicity isn’t always enough to solve complex problems.</p>
<p>Everyone wants simplicity. Customers, for instance, love services like "Buy Now, Pay Later"—a simple way to shop without worrying about payment. What’s hidden behind this simplicity, though, is a complex system that manages loans and installment financing.</p>
<p>Simplicity is tempting, but opting for an overly simplistic system design for complex problems can lead to bigger issues down the road. While simple architectures work well for MVPs, what happens when your business needs to solve more than just simple problems?</p>
<h1 id="heading-definition-of-simple-architecture">Definition of Simple Architecture</h1>
<h2 id="heading-what-is-layered-architecture">What is Layered Architecture?</h2>
<p>In many software projects, <strong>layered architecture</strong> is a simple, commonly used approach. It divides the system into distinct layers, each with a specific responsibility. These layers typically include:</p>
<ul>
<li><p><strong>Presentation Layer</strong>:<br />  This layer handles external interactions. In <strong>frontend (FE)</strong> projects, it deals with the UI and user input. In <strong>backend (BE)</strong> projects, it typically handles API requests and responses (controllers).</p>
</li>
<li><p><strong>Business Logic Layer</strong>:<br />  The core of the system, where business rules and logic are implemented. This layer focuses on fulfilling stakeholder requirements, abstracting away technical details.</p>
</li>
<li><p><strong>Persistence Layer</strong>:<br />  Responsible for interacting with storage systems (like databases). It usually contains functions or methods for reading from and writing to databases.</p>
</li>
<li><p><strong>Database Layer</strong>:<br />  This is where your data resides. Whether it's a relational database, NoSQL, or in-memory database, this layer manages data storage, schema design, indexing, and keys (such as in Redis).</p>
</li>
</ul>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfzQqa9eAa3SDUACI4f_ZiZ9AEB8cPSgAfKPtunFZMBuWLilI7n_1AaFt9L6LOy7vAE28pAvoaJ61qa9DcsULuRUR7l8o0H8zNRvXGMTwi5icfOUrA0jpt0IG032y7NASo6ju0bhA?key=wFLpdJFSRCuyuKWBoKz4nP33" alt="Diagram illustrating four software architecture layers: Presentation Layer, Business Layer, Persistence Layer, and Database Layer, connected by arrows indicating flow." /></p>
<h2 id="heading-how-it-works">How It Works</h2>
<p>Layered architecture follows the <strong>separation of concerns</strong> principle, meaning that each layer is responsible for its specific tasks. The layers are <strong>technically partitioned</strong>—each group of components solves a specific technical role within the system.</p>
<p>One of the key rules in layered architecture is how components <strong>interact across layers</strong>. Notice in diagram below, where Services component is interacting to Entity, then Entity is interacting to Value Object.</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeIJBXkkP3FaJJ2JSfrs_-Se6Ti_c-D_a6_E44m3uTT4_50mrV0bsg9Lb69KeR8DbgC1ngxpJ8fA0HlPjoR_HWi3qtLiFAHUWKPKk9UizIT_kEOHB3Tzpr_yXTS7y6M_xACsG-F?key=wFLpdJFSRCuyuKWBoKz4nP33" alt="Hand-drawn diagram of software architecture with four layers: Presentation Layer (Controller A, Controller B), Business Layer (Services, Entity, Value Object), Persistence Layer, and Database Layer. Arrows indicate data flow." /></p>
<p>Typically, components in a higher layer (e.g., Presentation) can access components in the layers below (e.g., Business Logic or Persistence), but <strong>lower layers</strong> cannot directly call higher layers.</p>
<p>However, in practice, challenges arise. For example, you may run into issues where components from different layers need to communicate, or you might be tempted to <strong>skip a layer</strong> to make development more convenient (e.g., bypassing the Business Logic layer to directly query the database).</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdpFVLyHUYKEskv1RzV_iyy6Z3KHzbE_hSAPTSxq-AvIQo1L5GBCae8vNLGqnMbVqc9UYvifYx5FHfPTdQEgl2wTzOZFBtwttntEuHBF7KqEnxQY2zCs-z4ub5mq1cUZ8QpBBSA?key=wFLpdJFSRCuyuKWBoKz4nP33" alt="Diagram of a multi-layer architecture. It includes a Presentation Layer with Controller A and B, a Business Layer with Services and Entity, a Persistence Layer with Repository, and a Database Layer. Arrows indicate interactions between components." /></p>
<p>While this architecture is intentionally <strong>simplistic</strong>, it works well when a project is starting out, as the clear separation between layers makes it easy to organize and manage the application.</p>
<h1 id="heading-when-to-use-and-when-not-to-practical-tips">When to Use (and When Not To) — Practical Tips</h1>
<ol>
<li><p>It is good for starters.<br /> Layered architecture is an excellent choice for beginners due to its simplicity and clear structure. It provides a solid foundation for understanding basic architectural principles without overwhelming complexity.</p>
</li>
<li><p>Use it on small to medium-sized applications.<br /> This approach works well for applications that don’t require extensive scalability or performance optimization. For small to medium projects, it ensures maintainability and straightforward implementation.</p>
</li>
<li><p>Clear, well-defined separation of concerns.<br /> The architecture promotes a clean separation of concerns, with each layer focusing on a specific responsibility. This makes the codebase easier to understand, test, and maintain.</p>
</li>
<li><p>Avoid it for complex systems with evolving requirements.<br /> Layered architecture struggles to adapt to complex systems with dynamic and growing requirements. Its rigid structure can lead to bottlenecks and difficulty scaling as the project evolves.</p>
</li>
<li><p>Not for high-performance apps.<br /> Applications requiring high performance may outgrow the layered approach, as the additional abstraction layers introduce latency and can become a limiting factor under heavy load.</p>
</li>
<li><p>Prevent using it for systems with dynamic needs.<br /> Systems with rapidly changing or unpredictable requirements demand flexibility, which layered architecture lacks. It is best suited for stable environments where requirements are well-defined.</p>
</li>
</ol>
<h1 id="heading-my-thought-on-layered-architecture">My Thought on Layered Architecture</h1>
<p>After the microservices hype, <strong>simple architectures</strong> gained attention. At first people use microservice as a silver bullet, making a lean engineering team to manage dozens of services that could be handled with a more straightforward <strong>layered architecture</strong>. This again created a misunderstanding, where <strong>layered architecture</strong> was seen as a one-sizes-fits-all solution, without considering how projects could evolve into more complex systems over time.</p>
<p>In some cases, teams are <strong>tempted</strong> to apply a simplistic design to an already <strong>complex problem</strong>, which can backfire as the project grows. <strong>Understanding the limits of simplicity</strong> is crucial, as it might lead to difficulties down the line.</p>
<p>My advice: <strong>understand when simple architecture is appropriate</strong> and, just as importantly, when it isn’t. Knowing the right time and context for applying this approach is key to managing complexity in evolving projects.</p>
<p>Let’s continue the discussion in the comment section, on why layered architecture is not suited for complex problem 🙌</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>While a simple layered architecture can work well for smaller applications or well-defined problems, it is not a one-size-fits-all solution. As software problems grow in complexity, the need for a more flexible and scalable architecture becomes apparent. If you're working on a complex system, consider adopting an architecture that supports flexibility and scalability from the beginning.</p>
<p>Are you working on a system that could benefit from a more complex architecture? Share your experience in the comments or reach out to discuss how you can optimize your software architecture for the challenges ahead.</p>
]]></content:encoded></item><item><title><![CDATA[Do we agree, to disagree?]]></title><description><![CDATA[When I was a pupil during the early day of my career, I knew absolutely nothing. What I could do is listen to what my senior said and did whatever told me to.
But hey, we also asked to raise our opinion. They say, because discussion matters. Eventual...]]></description><link>https://satria.technology/do-we-agree-to-disagree</link><guid isPermaLink="true">https://satria.technology/do-we-agree-to-disagree</guid><category><![CDATA[discussion]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Thu, 09 Feb 2023 04:33:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/oRavIk04N10/upload/994c36cdd42d82d0cb353d1d1591d539.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I was a pupil during the early day of my career, I knew absolutely nothing. What I could do is listen to what my senior said and did whatever told me to.</p>
<p>But hey, we also asked to raise our opinion. They say, because discussion matters. Eventually, we will make an agreement on how things will be done. It requires everybody to <strong>commit</strong> to the result of the discussion.</p>
<p>For these past few months, I have just realized what the word "commit" truly means. You can find more the <a target="_blank" href="https://www.merriam-webster.com/dictionary/commit">details here</a>, I believe the one that we all mean is this "<em>to carry into action deliberately</em>".</p>
<p>But, what if our heart doesn't go with the discussion? We feel that this discussion is a waste of time because they started it all wrong. Committing to something requires our heart and passion, what if we do not agree with that? Burn out, huh? Need some healing?</p>
<p>For me, I was told to be bold about something I believe until someone gives a reasonable argument, then we change our beliefs little by little. A bit frustrating to be honest, even for myself. But what if the argument is completely unreasonable for us but everybody agrees with them? Am I wrong here?</p>
<p>That's when I first heard about the idea of <strong>agree to disagree</strong>.</p>
<p>As a newbie, I might be wrong about what it truly is. <a target="_blank" href="https://en.wikipedia.org/wiki/Agree_to_disagree">The Wikipedia's explanation</a> about this is when all parties tolerate but do not accept the opposing positions. In my opinion, this is what we can do when we happen to be in this position in a professional working situation.</p>
<p><strong>The discussion must come to an end,</strong> because we have a limit to perform the discussion. The business keeps going on during our debate, but it needs our discussion to be resolved fast. Not everyone agrees but put simply the best bet and asks everybody to commit, at least for now.</p>
<p><strong>There always be another time</strong>. I mean, if you could not prove your argument now, there will always be another time to convince others. In a discussion, everyone's voices are not treated equally. Frankly, it might happen when you sit close enough with your leader, making your leader listen to you more. Or, your microphone is not performing well when discussing over an online meeting.</p>
<p><strong>Act professional</strong>. Speaking your idea is an act of professionalism, opposite to silence. As a white collar, you are paid to express your idea. When you do not speak, you might consider changing your career to a blue-collar role. But hey, it is not that bad to express an opposite idea to others. Most of the time, I feel relieved when listening to the opposite idea.</p>
<p>So guys, next time we run to a discussion, do we agree to disagree?</p>
]]></content:encoded></item><item><title><![CDATA[Different Types of Unit Test Strategy]]></title><description><![CDATA[I witness some ways of doing unit tests during my career.
I learned all of those from learning a new language and then finding the unit test framework people typically use. Various frameworks teach us different ways of making unit test, they even tea...]]></description><link>https://satria.technology/different-types-of-unit-test-strategy</link><guid isPermaLink="true">https://satria.technology/different-types-of-unit-test-strategy</guid><category><![CDATA[unit testing]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Thu, 26 Jan 2023 15:39:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/JXIFjYVbAS8/upload/2974aa12364c6d4b3e7f8fc7006e0bd8.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I witness some ways of doing unit tests during my career.</p>
<p>I learned all of those from learning a new language and then finding the unit test framework people typically use. Various frameworks teach us different ways of making unit test, they even teach us the philosophy of unit tests.</p>
<p>It might not be a complete reference of various unit test strategies existing in this world, so if I missed some important thing, please let me know then I can make an update for the next persons coming.</p>
<h2 id="heading-problem-with-testing">Problem With Testing</h2>
<p>Before moving to the point, I would like to brief you this simple problem of how to create a unit test for the very smallest part of your code.</p>
<p>Sometimes, we didn't have much choice when the existing code has been equipped with a unit test. As a n-th person working toward the code, your job is to make that unit test all green withstanding your very current changes. Some changes on the unit test may be required, or you may need to add new cases to an existing one.</p>
<p>When there is no existing unit test or you make radical changes to the code, you will mostly need to think about how to write the unit test. You want it to be simple enough to write, yet convincing enough to withstand future unlimited alteration.</p>
<h2 id="heading-behaviour-driven">Behaviour Driven</h2>
<p>This one is by far the easiest to understand because it is so intuitive to think about. To put it simply, our flow must behave somewhat according to what we desire. To work with this strategy, you may need to write down some cases with preconditions, actions, and a set of expectations.</p>
<p>It is easier for other developers to read. Most unit testing frameworks that go with this strategy require us to write a simple and meaningful comment.</p>
<p>Most of the frameworks using this strategy also uses Gherkin notation, it is even very convenient if you are serious about assuring your code through the unit test.</p>
<h2 id="heading-test-coverage-driven">Test Coverage Driven</h2>
<p>The unit test may be not on your agenda so far. At then end, you still need to convince everyone that you have a set of unit tests to withstand future changes. So far, I believe this strategy is the easiest one to encourage people to write it because it has a clear quantitative measure.</p>
<p>I don't prefer this strategy of writing unit test. It encourages you to leave something when you may haven't. Since you have written a unit test that went through these lines, there is no point to add another going through these.</p>
<p>Let's be honest, we prefer to use this strategy because we can show this to our manager right?</p>
<h2 id="heading-test-table">Test Table</h2>
<p>Test table comes in very handy, sometime you don't need any testing framework to write one. For newbies, coming up with the idea of writing a test table is surprising. I even hadn't seen that until someone wrote a test table on our code base.</p>
<p>Other than behaviour-driven, the test table is also my favourite when you have a very simple unit to test. For me, it could be a tiny function that branched out to improve the readability of the main flow. We can then bombard this small function with tons of cases.</p>
<h2 id="heading-whats-next">What's next?</h2>
<p>I also wondered up to this point, what would you need to know after knowing all of this? For me, I would like to know a real example of unit test, some parts of me wants to know the step by step of planning to write a unit test.</p>
<p>Let me know if you want to know something.</p>
]]></content:encoded></item><item><title><![CDATA[Async Architecture: Message Queue]]></title><description><![CDATA[Problem
You have a service that has a dynamic load of incoming traffic to perform heavy-weight operations. Luckily, the client doesn't demand an immediate response from our service.
If possible, we still need to deliver the result fast enough, becaus...]]></description><link>https://satria.technology/async-architecture-message-queue</link><guid isPermaLink="true">https://satria.technology/async-architecture-message-queue</guid><category><![CDATA[message queue]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Wed, 25 Jan 2023 01:38:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/pT4gB7T6tog/upload/b0bffdeb9413455f819628a8f6609aed.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-problem">Problem</h2>
<p>You have a service that has a dynamic load of incoming traffic to perform heavy-weight operations. Luckily, the client doesn't demand an immediate response from our service.</p>
<p>If possible, we still need to deliver the result fast enough, because the client doesn't want to wait any longer.</p>
<h2 id="heading-solution">Solution</h2>
<p>Let's say we have a service named <strong>P</strong>, which always receives operation requests from clients.</p>
<p>Service <strong>P</strong> will forward any requests to a queue named <strong>Q</strong>. Every time service <strong>P</strong> successfully forward the request, the client needs to wait for the result of the operation.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674569999117/685ada7a-a049-4512-9f8b-038bb26870fa.png" alt class="image--center mx-auto" /></p>
<p>On the other side, there is <strong>n</strong> number of service <strong>C.</strong> Every service <strong>C[i]</strong> will consume any possible request from queue <strong>Q</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674570117302/058c661f-128e-4877-8c92-8ae7f6e1e5d7.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-normal-case">Normal Case</h3>
<p>Under the hood of queue <strong>Q</strong> and every n of service <strong>C</strong>, you will notice for every request will only be processed by one of any possible service <strong>C</strong>. This is a very important remark that becomes what a message queue is.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674570654389/fbc84d56-a624-4fbb-b16c-8f8fdf4e502a.png" alt class="image--center mx-auto" /></p>
<p>After a service has begun processing a request, the next request is available for processing for any available service <strong>C</strong>. But that request is not effectively gone from the queue <strong>Q</strong>.</p>
<p>Service C shall give an indication, of whether it needs to be ACK (success and ok to delete) or NACK (error and no for delete). When that request is given an ACK command, we won't have a further issue.</p>
<h3 id="heading-handling-nack">Handling NACK</h3>
<p>NACK is used as an indication that the operation of the request is failed. Retry would do, and we can give it a try. But we need to set some limits on that.</p>
<ol>
<li><p>Simply just re-queue</p>
</li>
<li><p>Re-queue and track</p>
</li>
<li><p>Send to dead letter queue</p>
</li>
</ol>
<p><strong>Simply just re-queue</strong> a request. This is typicaly of what service C will do. Hoping the next service C that will process this request will do just fine. If there are <strong>n</strong> number of service C and there are <strong>n-1</strong> needed to be requeued, there is at least one service C that will process the remaining request. It means the queue still moves on.</p>
<p><strong>Re-queue and track</strong> how long it has been re-queued. We may need to give special treatment after some retrying.</p>
<p><strong>Send to the dead letter queue</strong> would be the best option to send this problematic request to the dedicated queue of problematic requests. We might need to take a look at this queue later manually.</p>
<hr />
<p>References:</p>
<ul>
<li><a target="_blank" href="https://www.rabbitmq.com/tutorials/tutorial-two-python.html">https://www.rabbitmq.com/tutorials/tutorial-two-python.html</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Requirement Analysis Would Never be The Same]]></title><description><![CDATA[As a Software Engineer with 4 years of working experience, we are asked to deliver a product out of nothing but idea.
Software Development Life-Cycle (SDLC) comes in various styles and practices, but formally we have these processes:

Analysis

Desig...]]></description><link>https://satria.technology/requirement-analysis-would-never-be-the-same</link><guid isPermaLink="true">https://satria.technology/requirement-analysis-would-never-be-the-same</guid><category><![CDATA[Software Development Life Cycle(SDLC)]]></category><category><![CDATA[requirement analysis]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Sun, 15 Jan 2023 15:14:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/--kQ4tBklJI/upload/09463c293aeb224e478dd09e64e655d1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a Software Engineer with 4 years of working experience, we are asked to deliver a product out of nothing but idea.</p>
<p>Software Development Life-Cycle (SDLC) comes in various styles and practices, but formally we have these processes:</p>
<ol>
<li><p>Analysis</p>
</li>
<li><p>Design</p>
</li>
<li><p>Development</p>
</li>
<li><p>Testing</p>
</li>
<li><p>Deployment</p>
</li>
<li><p>Documentation</p>
</li>
<li><p>Maintenance</p>
</li>
</ol>
<p>For me, the "Analysis" is the hardest part. In this article, I would like to tell you why upfront requirement analysis is so important and how to deal with the way high pace startup works.</p>
<h1 id="heading-what-is-requirement-analysis">What is Requirement Analysis</h1>
<p>Its goal is for us to have an understanding of the business requirement. To be able to do that, formally we can set this three outputs:</p>
<ol>
<li><p>Scope of Work</p>
</li>
<li><p>Options evaluation</p>
</li>
<li><p>Cost-benefit</p>
</li>
</ol>
<p>Most of the time, we often only produce "Scope of Work", because intuitively it can save our ass when we were missing some features.</p>
<p>Evaluating possible options could give us the grand picture of what would it look like. It is also a way to have mutual knowledge with the product owner. Remember, the word "options" is plural, then we need to produce some.</p>
<p>As a professional Software Engineer, we must communicate the possible cost and demonstrate the benefit of each option. The product owner will find it very helpful. It also prevents underestimate and overestimate feeling from stakeholders toward us.</p>
<h1 id="heading-miss-conception-of-requirement-analysis">Miss Conception of Requirement Analysis</h1>
<p>Waterfall methodology as in SLDC is something Every computer science graduate should know, and also everyone hated. Got their first job working in Waterfall, and believe me, they will be begging for their life to move on.</p>
<p>For some reason, I often got confused when performing requirement analysis means we are going back to the way Waterfall does: <strong>doing it up first, continuing with the upcoming process, and never going back.</strong></p>
<p>Working in a high pace startup with a very ambitious and tight deadline, for example, it is normal that we tend to skip taught-to-be non-essential formal processes. I agree that we need working software as our top priority, but how can we do that when not understanding the requirement?</p>
<p>Even in a near-perfect environment, performing requirement analysis also tend to be forgotten. Try to imagine, we are given very detailed business requirements, access to the business team, communicative product owner. The very first thing we gonna do is jumping into coding, what a shame.</p>
<p>I am not suggesting holding back product delivery with a mouthful of discussion. What we assume to be a mouthful, actually is something fruitful later process in our SDLC.</p>
<h1 id="heading-when-working-in-a-high-pace-startup">When Working in a High Pace Startup</h1>
<p>Those who are very fans of the startup movement will find a time-consuming analysis as something wasteful. I agree with them though. Spending too much time thinking will not get us anywhere, but leads us to useless overthinking.</p>
<p>When I was reading Lean Startup, it just clicks into my mind, as a Software Engineer we tend to overdo analysis, design, and even coding!</p>
<p>Lean Startup tells us, to handle the uncertain reality of the business we need a fast and frequent feedback loop: build, measure, learn</p>
<p>Lean Startup is talking about business and product development, but I find resonance with what we are doing in software engineering. Since the business and product team is working under an uncertain business reality, so do we when facing product requirements. By applying this fast and frequent feedback, we are hoping to see high-quality software day by day.</p>
<p>We expect ourselves to analyze requirements differently by now:</p>
<ol>
<li><p>Tactical win vs strategic movement;</p>
</li>
<li><p>Just do it, look it for ourselves;</p>
</li>
<li><p>Be friends with data usage: log, metrics, data, etc.</p>
</li>
</ol>
<h1 id="heading-first-step-toward-perfection">First Step toward Perfection</h1>
<p>Learning by doing is the best learning method for beginners. So, there are some ways for us to practically learn how to perform requirement analysis better in a high pace startup environment.</p>
<p><strong>Expose yourself to the discussion</strong>. When your product owner or tech lead presents the very basic background and product requirements, don't just stare at them blankly. Write a note, make some questions, and draw a diagram to make you understand. Direct communication is the most effective communication for thousands of years now, don't let this timing getaway.</p>
<p><strong>The discussion is still running on</strong>, even after everyone has agreed. Leave a comment on the requirement, ask some questions, and ask for clarification.</p>
<p><strong>Write something</strong>, talk is cheap and it will spoil in no time. Writing your requirement analysis will make your argument comes stronger than anyone. My experience proves it, we do not need a sexy leadership role to influence the technical decision.</p>
<p><strong>Remember the formula</strong>, it will help you on performing the analysis. Requirement analysis produces the scope of work, choices evaluation, cost-benefit.</p>
]]></content:encoded></item><item><title><![CDATA[Working Experience over Portfolio]]></title><description><![CDATA[As a computer science college student, I was so passionated to become software engineer. I had learnt that following college curriculum is not enough to take me to my dream, then I needed to learn practical knowledge such as backend, frontend, etc.
I...]]></description><link>https://satria.technology/working-experience-over-portfolio</link><guid isPermaLink="true">https://satria.technology/working-experience-over-portfolio</guid><category><![CDATA[Job Hunting]]></category><category><![CDATA[portfolio]]></category><category><![CDATA[Learning Journey]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Sun, 09 Oct 2022 13:20:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/6d5I1-gixyU/upload/v1665321525531/co2s-0QnQ.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a computer science college student, I was so passionated to become software engineer. I had learnt that following college curriculum is not enough to take me to my dream, then I needed to learn practical knowledge such as backend, frontend, etc.</p>
<p>It is always important to showcase our achievement. When we were learning backend for example, then you need to tell your future employer that you are worth to hire. The only way that came up to me was portfolio, certification was not really a thing 4 years ago at least on my circle.</p>
<p>Working on portfolio gives validation that you gain something from your learning journey. It is a milestone that you have already passed certain level.</p>
<p>Building a portfolio was not suited to my learning characteristic. I got intrigued to learn everything until I became confused on what to learn. For example, choosing programming language to pick was not an easy stuff. After I had decided the language, some said that we need to master specific framework popular enough.</p>
<p>The thing is, building a portfolio wasn't really great.</p>
<p>I don't quite asked on my portfolio when conducting technical interview. During my first job hunting, it was take home project that they were interested to. They did ask much a glimpse of my portfolios.</p>
<p>Later when I was looking my second employer, they asked me on my working experience. Something that I did for my past employer.</p>
<p>If I had known working experience matters most, I would not have been working on portfolio, I would have got working experience like internship or part time. A true and real working experience that I can tell to recruiter, rather than something imaginary of made up usecase (portfolio).</p>
<p>I am not saying portfolio is a bad thing and everyone should avoid working on it. Here, I am giving you an option that might need more attention: working experience.</p>
<p>You may have problem on finding your first job because you don't have any experience at all. That's when portfolio matters the most. But you need to be aware, your first job is a part of your learning journey, hence you do not need to work all out on the portfolio.</p>
<p>As long as you learn something, able to create a simple demonstrative portfolio to validate your knowledge, you do not need to go any further to just get your first job.</p>
<p>I wish we have a good luck on our software engineer career journey.</p>
]]></content:encoded></item><item><title><![CDATA[Don't waste your time on CRUD]]></title><description><![CDATA[CRUD (Create, Read, Update, Delete) is a set of basic persistent operation on a module can do. For example, your company comes to manage a marketing event. The CRUD of this marketing is when it can create an event, get the list or individual event, u...]]></description><link>https://satria.technology/dont-waste-your-time-on-crud</link><guid isPermaLink="true">https://satria.technology/dont-waste-your-time-on-crud</guid><category><![CDATA[No Code]]></category><category><![CDATA[Low Code]]></category><category><![CDATA[Learning Journey]]></category><dc:creator><![CDATA[Satria H R Harsono]]></dc:creator><pubDate>Mon, 03 Oct 2022 15:01:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/6Wax86m-3K4/upload/v1664809191289/W3QmlwBjT.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>CRUD (Create, Read, Update, Delete) is a set of basic persistent operation on a module can do. For example, your company comes to manage a marketing event. The CRUD of this marketing is when it can create an event, get the list or individual event, update event, ultimately delete event. 🚀</p>
<p>This is something we had always done in coding tutorial. Since we met it in the very first phase of our learning, we often underestimate it.</p>
<p>We are now talking about complex data structure on our module, it is something that difficult to draw in ER diagram. Next, how are we going to create an object of that. How do we even update that? Think of a set of rule that will limit our CRUD operation.</p>
<p>Don't underestimate things shall we? 🧐</p>
<p>And now, you are living in 2022 when they pay you millions but you are dragging a critical mission about months. Shame on you, you get it over and over in the tutorial but you still could not get fast? 😳</p>
<p>Well, I do not blame you. We always drag others. Not because we are bad, but the problem does require a significant amount of attention on us.  Be happy, you are still worth it to pay that much 😆</p>
<p>Again, you are living in 2022, or you have passed already. Stack Overflow is our best friend, we also have Reddit if SO doesn't give us any good. Even, there are bunches of people who have been writing an interesting project which exactly solves your problem.</p>
<p>By the way, we are still talking about CRUD. Did you know there is a long live open source project that can give you a rich feature back office admin dashboard called <a href="https://github.com/directus/directus">Directus</a>?</p>
<p>Directus can give you a boost where you only need to think about the data structure, where it can help you for the CRUD. I use it for my latest personal project!</p>
<p>For you who greed enough, there even open source project that can give you both front end and back end. I have been seen it quite sometime, <a href="https://github.com/Budibase/budibase">Budibase</a>, it even seems as shiny as directus does. Can not wait to test it on production.</p>
<p>I did not get a chance to really invest on boilerplate, which I believe there are tons of it already in you favorite languages.</p>
<p>But, let's be honest. We often prefer write it from scratch than adopt existing one. The true reason that I feel mostly is adopting new one requires time and effort to learn. Just spit it, we are too board to learn.</p>
<p>At least, that was my case. I hope you are not, because again you are too expensive just to work on these repetitive works. Better to allocate your brain on scalability issue that has been around for sometime in your company.</p>
]]></content:encoded></item></channel></rss>