<?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[Diurnal/Trail]]></title><description><![CDATA[Passionate software builder for a better web that enable, not replace people.]]></description><link>https://blog.nadhif.dev</link><generator>RSS for Node</generator><lastBuildDate>Sat, 23 May 2026 00:55:28 GMT</lastBuildDate><atom:link href="https://blog.nadhif.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Environments Handbook]]></title><description><![CDATA[I switched contexts a lot when using technologies, either for work or personal projects, constantly remembering my existing config are overwhelming
Primarily for personal guide.

Essentials

I moved from WebStorm to use VSCode. As it’s getting too sl...]]></description><link>https://blog.nadhif.dev/environments</link><guid isPermaLink="true">https://blog.nadhif.dev/environments</guid><category><![CDATA[configuration]]></category><category><![CDATA[Environment]]></category><dc:creator><![CDATA[Nadhif Ikbar Wibowo]]></dc:creator><pubDate>Wed, 15 Jan 2025 03:14:04 GMT</pubDate><content:encoded><![CDATA[<p>I switched contexts a lot when using technologies, either for work or personal projects, constantly remembering my existing config are overwhelming</p>
<p>Primarily for personal guide.</p>
<hr />
<h1 id="heading-essentials">Essentials</h1>
<ul>
<li><p>I moved from WebStorm to use VSCode. As it’s getting too slow to handle medium-sized monorepo while waiting Windows stable build for <a target="_blank" href="https://zed.dev/">Zed</a></p>
</li>
<li><p><a target="_blank" href="https://berkeleygraphics.com/typefaces/berkeley-mono/">Berkeley Mono Typeface</a></p>
</li>
<li><p><a target="_blank" href="https://bitwarden.com/"><strong>Bitwarden</strong></a></p>
</li>
</ul>
<hr />
<h1 id="heading-windows">Windows</h1>
<h2 id="heading-terminal">Terminal</h2>
<p>Enhanced <code>cmd.exe</code> by defining couple aliases, saved in <code>%userprofile%\alias.cmd</code>. Private alias.cmd is used</p>
<h3 id="heading-gnu-utilities">GNU utilities</h3>
<p>Git for Windows is built on top of <em>patched</em> MSYS2 to make git works better in Windows pathing system, they also ship small subsets of familiar GNU utilities like <code>ls</code>, <code>mkdir</code>, etc built to work for Windows, to make this available via terminal, I exposed <code>C:\Program Files\Git\usr\bin</code> path which contains such executables.</p>
<blockquote>
<p>Due to requirement of C family toolchains, for example <code>gcc</code>, MSYS2 is used to provides this toolchain in Windows. Default install <code>C:\msys64</code>.</p>
<p>Note: make sure to provide paths for MSYS2 binaries <strong>BEFORE</strong> Git for Windows to as Git for Windows to prevent common executable conflicts.</p>
</blockquote>
<p>Other than that, it's generally preferred to use binaries from Git for Windows because of the likelihood of its included binaries has been patched to handle Windows pathing system better.</p>
<p><strong>Caveat!</strong> Git for Windows and MSYS2 binaries paths might also contain executables that are natively included by Windows (example: <code>ssh</code>), using Windows built-in binaries are typically always preferred.</p>
<p>To make interop easier to deal with, <strong>make sure to expose these built-in binaries paths BEFORE MSYS2 and Git for Windows</strong>. Check interop correctness especially for <code>gpg</code> by GnuPG and <code>ssh</code> from built-in OpenSSH.</p>
<h2 id="heading-tooling">Tooling</h2>
<ol>
<li><p><a target="_blank" href="https://www.rapidee.com/en/about">Rapid Environment Variables</a></p>
</li>
<li><p><a target="_blank" href="https://diskanalyzer.com/">WizTree</a></p>
</li>
</ol>
<h2 id="heading-useful-fixes-for-windows">Useful Fixes for Windows</h2>
<ol>
<li><a target="_blank" href="https://superuser.com/questions/1319157/some-windows-10-uwp-icons-not-displaying-on-search-or-in-settings">Missing UWP Icons due to Google Drive File Streams</a></li>
</ol>
<hr />
<h1 id="heading-macos">MacOS</h1>
<p><a target="_blank" href="https://brew.sh/">homebrew</a> as main package manager</p>
<h2 id="heading-terminal-1">Terminal</h2>
<blockquote>
<p>This terminal section also applies for WSL2</p>
</blockquote>
<p>MacOS has been shipping <code>zsh</code> by default, I avoid bloating my terminal with too many plugins, fast startup and staying lightweight are preferred.</p>
<blockquote>
<p>Set <code>zsh</code> as default sh for WSL2: <code>chsh -s $(which zsh)</code></p>
</blockquote>
<p>Setup: <a target="_blank" href="https://github.com/zdharma-continuum/zinit?tab=readme-ov-file">install zdharma-continuum/zinit</a> and configure</p>
<pre><code class="lang-plaintext"># Remove defualt ~/.zshrc that might be created during your first `zsh` run
# Add to ~/.zshrc after installing zdharma-continuum/zinit
# After the `Zinit` autoload block

zinit for \
    light-mode \
  zsh-users/zsh-autosuggestions \
    light-mode \
  zdharma-continuum/fast-syntax-highlighting \
  zdharma-continuum/history-search-multi-word \
    light-mode \
    pick"async.zsh" \
    src"pure.zsh" \
  sindresorhus/pure
</code></pre>
<blockquote>
<p>In WSL2, syntax-highlight have performance issues due the inclusion of Windows paths by default. To improve performance, excluding Windows paths can be done by following <a target="_blank" href="https://github.com/zsh-users/zsh-syntax-highlighting/issues/790">this</a>. But following the guide might also remove desired binaries from system path, e.g <code>code</code> for VSCode. It can be added back by creating function that act as alias that handle arguments passing.</p>
</blockquote>
<pre><code class="lang-bash"><span class="hljs-comment"># .zshrc</span>
<span class="hljs-function"><span class="hljs-title">code</span></span>() {
    /mnt/c/Program\ Files/Microsoft\ VS\ Code/bin/code <span class="hljs-string">"<span class="hljs-variable">$@</span>"</span>
}
</code></pre>
<hr />
<h1 id="heading-language">Language</h1>
<h2 id="heading-java">Java</h2>
<ul>
<li>Adoptium JDK 21 via Homebrew for MacOS, directly on Windows</li>
</ul>
<h2 id="heading-python">Python</h2>
<ul>
<li><p>Via <a target="_blank" href="https://docs.astral.sh/uv/"><code>uv</code></a></p>
</li>
<li><p>You generally don’t want to replace system python. Use virtualenv instead.</p>
</li>
</ul>
<h2 id="heading-go-golang">Go (Golang)</h2>
<ul>
<li>Direct install</li>
</ul>
<h2 id="heading-javascriptnodejs">Javascript/Node.js</h2>
<ul>
<li><p>Use <code>nvm</code> to maintain installed node version. <a target="_blank" href="https://github.com/coreybutler/nvm-windows">Windows</a> | MacOS/WSL2</p>
</li>
<li><p><a target="_blank" href="https://pnpm.io/">https://pnpm.io/</a> is now preferred</p>
</li>
</ul>
<h2 id="heading-msys2-for-c-developement-windows">MSYS2 for C Developement (Windows)</h2>
<ul>
<li><p>Install MSYS2</p>
</li>
<li><p>For Clang/LLVM toolchain (recommended)</p>
<ul>
<li><code>pacman -S mingw-w64-ucrt-x86_64-clang</code></li>
</ul>
</li>
<li><p>For GCC</p>
<ul>
<li><code>pacman -S mingw-w64-ucrt-x86_64-gcc</code></li>
</ul>
</li>
<li><p>Recommended to just use UCRT - <a target="_blank" href="https://stackoverflow.com/questions/67848972/differences-between-msvcrt-ucrt-and-vcruntime-libraries">Why UCRT?</a></p>
</li>
<li><p><a target="_blank" href="https://www.msys2.org/docs/environments/">MSYS2 Environments</a></p>
</li>
</ul>
<p>Notes about MSYS2’s common GNU binaries - <a class="post-section-overview" href="#gnu">above</a>.</p>
<hr />
<h1 id="heading-git">Git</h1>
<blockquote>
<p>Use <a target="_blank" href="https://gitforwindows.org">Git for Windows</a> then expose git binaries path</p>
<p>Use Git from Homebrew for MacOS.</p>
</blockquote>
<h2 id="heading-commit-signing">Commit Signing</h2>
<ol>
<li><p>Enable GPG signing globally <code>git config --global commit.gpgsign true</code>.</p>
</li>
<li><p>By default git will use <code>gpg</code> command by default to perform signing.</p>
</li>
<li><p>Then you need to tell <a target="_blank" href="https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key#telling-git-about-your-gpg-key">which GPG key to use</a> for signing.</p>
</li>
</ol>
<p>Windows-only note</p>
<blockquote>
<p>By installing GnuPG (GPG) individually, you can use <code>gpg</code> command on Windows. But it's easier to install it via <a target="_blank" href="https://www.gpg4win.org/about.html">GPG4Win</a> which also includes Kleopatra (make sure to tick it during installation) that provide interface for GPG keys &amp; settings management e.g passphrase TTL.</p>
<p>When freshly installing GPG4Win, make sure to also follow <a target="_blank" href="https://gist.github.com/matusnovak/302c7b003043849337f94518a71df777#start-the-agent-on-startup">Start The Agent on Startup guide</a> right after</p>
</blockquote>
<h2 id="heading-associating-gpg-key-with-email-on-git-provider">Associating GPG key with email on Git provider</h2>
<p>To make sure git provider recognize signed commit properly, they need to associate an email with certain GPG key, this should be done once.</p>
<ul>
<li><p><a target="_blank" href="https://docs.github.com/en/authentication/managing-commit-signature-verification/associating-an-email-with-your-gpg-key">Github</a></p>
</li>
<li><p><a target="_blank" href="https://docs.gitlab.com/ee/user/project/repository/gpg_signed_commits/#add-a-gpg-key-to-your-account">Gitlab</a></p>
</li>
</ul>
<h2 id="heading-use-windows-built-in-openssh-client-for-git-for-windows">Use Windows built-in OpenSSH client for Git for Windows</h2>
<p>With Windows including <code>ssh-agent</code> and OpenSSH client by default, this provide a lightweight and solid ssh baseline setup, just make sure to <a target="_blank" href="https://poshsecurity.com/blog/using-the-openssh-client-included-in-windows-10-1809-as-your-gits-ssh-client">config Git to use it for its ssh command</a></p>
<h2 id="heading-configure-wsl-to-use-windows-git-credential-managerhttpswwwedwardthomsoncombloggitcredentialmanagerwithwindowssubsystemforlinux"><a target="_blank" href="https://www.edwardthomson.com/blog/git_credential_manager_with_windows_subsystem_for_linux">Configure WSL to use Windows Git Credential Manager</a></h2>
]]></content:encoded></item><item><title><![CDATA[Idempotency in Automation]]></title><description><![CDATA[One characteristic of robust automation is to make sure that our script is idempotent, this is a big word that describes a behavior where our automation will produce the same end system state no matter how many times the automation is triggered.
Here...]]></description><link>https://blog.nadhif.dev/idempotency-in-automation</link><guid isPermaLink="true">https://blog.nadhif.dev/idempotency-in-automation</guid><category><![CDATA[automation]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[Nadhif Ikbar Wibowo]]></dc:creator><pubDate>Tue, 02 Mar 2021 16:51:51 GMT</pubDate><content:encoded><![CDATA[<p>One characteristic of robust automation is to make sure that our script is <strong>idempotent</strong>, this is a big word that describes a behavior where our automation will produce the same end system state no matter how many times the automation is triggered.</p>
<p>Here's a simple example of a non-idempotent vs idempotent implementation of a script that makes sure a list of directories exists and has the correct permission in a Linux environment:</p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/env python3</span>

<span class="hljs-keyword">import</span> os


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">resolve_path</span>(<span class="hljs-params">path</span>):</span>
    <span class="hljs-keyword">return</span> os.path.abspath(os.path.expanduser(path))

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_integrity</span>(<span class="hljs-params">dirs, mode=<span class="hljs-number">0o644</span></span>):</span>
    <span class="hljs-keyword">for</span> dir <span class="hljs-keyword">in</span> dirs:
       dir = resolve_path(dir)
       os.makedirs(dir)
       os.chmod(dir, mode)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    check_integrity([<span class="hljs-string">'~/.www'</span>, <span class="hljs-string">'~/.common'</span>])
</code></pre>
<p>This first implementation is non-idempotent because if the script is interrupted during its execution, the execution might raise an error because the script doesn't handle the system state where directories had already existed. To make it idempotent we can change it a little bit by passing <code>exists_ok=True</code> parameter.</p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/env python3</span>

<span class="hljs-keyword">import</span> os


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">resolve_path</span>(<span class="hljs-params">path</span>):</span>
    <span class="hljs-keyword">return</span> os.path.abspath(os.path.expanduser(path))

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_integrity</span>(<span class="hljs-params">dirs, mode=<span class="hljs-number">0o644</span></span>):</span>
    <span class="hljs-keyword">for</span> dir <span class="hljs-keyword">in</span> dirs:
       dir = resolve_path(dir)
       os.makedirs(dir, exists_ok=<span class="hljs-literal">True</span>)
       os.chmod(dir, mode)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    check_integrity([<span class="hljs-string">'~/.www'</span>, <span class="hljs-string">'~/.common'</span>])
</code></pre>
<p>Now the second script is idempotent because even if the script fails during its first execution when it's run again, it will produce the same end system state with no problem.</p>
<p>This example might seem a bit too obvious and trivial but it's enough to introduce the concept of idempotency. When we set up our automation to be idempotent we can expect our automation can fail during its execution because of factors we might haven't considered. To fix the problem we don't need manual intervention anymore instead we just need to run the script one more time.</p>
]]></content:encoded></item></channel></rss>