<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>kinbiko.com</title><link>https://kinbiko.com/</link><description>Recent content on kinbiko.com</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sun, 01 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://kinbiko.com/index.xml" rel="self" type="application/rss+xml"/><item><title>Installing Rockbox on an iPod Classic 7G with iFlash from Linux: a sector size odyssey</title><link>https://kinbiko.com/posts/2026-02-01-rockbox-ipod-classic-iflash-linux-sector-size/</link><pubDate>Sun, 01 Feb 2026 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2026-02-01-rockbox-ipod-classic-iflash-linux-sector-size/</guid><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This entire blog post was written by AI.
It is published because I want AI tools to more easily find and fix the problem I spent days debugging &amp;ndash; even with the assistance of AI.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you&amp;rsquo;re trying to install Rockbox on a flash-modded iPod Classic from Linux and getting
&amp;ldquo;No partition found&amp;rdquo;, you might be hitting the same invisible wall I did. The root cause
turned out to be a mismatch in virtual sector sizes between different USB modes &amp;ndash; something
that no guide I found online mentions. This post documents the problem and the fix.&lt;/p&gt;
&lt;h2 id="the-setup"&gt;
The setup
&lt;a class="heading-link" href="#the-setup"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;iPod Classic 7th generation (Apple model A1238, Rockbox target &lt;code&gt;ipod6g&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;iFlash adapter with a 512 GB SD card&lt;/li&gt;
&lt;li&gt;Arch Linux host (no macOS, no Windows, no iTunes)&lt;/li&gt;
&lt;li&gt;Rockbox built from source (commit &lt;code&gt;ee3e630&lt;/code&gt;, January 2026)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-symptom"&gt;
The symptom
&lt;a class="heading-link" href="#the-symptom"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;After partitioning the SD card, formatting it FAT32, installing the &lt;code&gt;.rockbox&lt;/code&gt; directory,
and flashing the bootloader via DFU, the iPod would boot to:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Rockbox boot loader
Version: ee3e630efa-260131
Battery status ok: 4081 mV
id: &amp;#39;1 CompactFlash C0000&amp;#39; s:512*1
No partition found
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The bootloader could see the storage device (the iFlash adapter identifies as CompactFlash)
and correctly detected 512-byte sectors with a physical sector multiplier of 1. But it
couldn&amp;rsquo;t find or mount any partition.&lt;/p&gt;
&lt;h2 id="the-dead-ends"&gt;
The dead ends
&lt;a class="heading-link" href="#the-dead-ends"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;h3 id="dead-end-1-the-old-bootloader-doesnt-support-4k-sectors"&gt;
Dead end 1: &amp;ldquo;the old bootloader doesn&amp;rsquo;t support 4K sectors&amp;rdquo;
&lt;a class="heading-link" href="#dead-end-1-the-old-bootloader-doesnt-support-4k-sectors"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;The pre-built Rockbox 4.0 bootloader gave the same error. Rockbox&amp;rsquo;s source code has a
sector multiplier loop in &lt;code&gt;disk.c&lt;/code&gt; that tries mounting partitions at 1x, 2x, 4x, and 8x
the MBR&amp;rsquo;s LBA values to compensate for virtual sector size mismatches. I built the
bootloader from source to make sure I had this code. The new bootloader failed identically.&lt;/p&gt;
&lt;h3 id="dead-end-2-the-cluster-size-is-too-large"&gt;
Dead end 2: &amp;ldquo;the cluster size is too large&amp;rdquo;
&lt;a class="heading-link" href="#dead-end-2-the-cluster-size-is-too-large"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mkfs.vfat -F 32&lt;/code&gt; on a 477 GiB partition with 4096-byte sectors chose 64 sectors per
cluster, producing 256 KB clusters. Rockbox&amp;rsquo;s &lt;code&gt;bpb_is_sane()&lt;/code&gt; rejects cluster sizes above
128 KB. Reformatting with &lt;code&gt;-s 8&lt;/code&gt; (32 KB clusters) fixed this check, but the &amp;ldquo;No partition
found&amp;rdquo; error persisted.&lt;/p&gt;
&lt;h3 id="dead-end-3-theres-a-stale-superfloppy-bpb-at-sector-0"&gt;
Dead end 3: &amp;ldquo;there&amp;rsquo;s a stale superfloppy BPB at sector 0&amp;rdquo;
&lt;a class="heading-link" href="#dead-end-3-theres-a-stale-superfloppy-bpb-at-sector-0"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;The iPod&amp;rsquo;s sector 0 had leftover FAT32 BPB bytes from a previous format that could confuse
Rockbox&amp;rsquo;s superfloppy detection (where it tries to mount sector 0 directly as a filesystem
before checking the partition table). Zeroing the first 446 bytes of sector 0 eliminated
this, but didn&amp;rsquo;t help.&lt;/p&gt;
&lt;h2 id="the-actual-problem-virtual-sector-sizes"&gt;
The actual problem: virtual sector sizes
&lt;a class="heading-link" href="#the-actual-problem-virtual-sector-sizes"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what was actually happening. It took reading the Rockbox bootloader source code to
figure it out.&lt;/p&gt;
&lt;h3 id="the-iflash-adapter-uses-512-byte-sectors"&gt;
The iFlash adapter uses 512-byte sectors
&lt;a class="heading-link" href="#the-iflash-adapter-uses-512-byte-sectors"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;The iFlash adapter&amp;rsquo;s SD card storage uses standard 512-byte sectors at the ATA level. The
bootloader confirms this with &lt;code&gt;s:512*1&lt;/code&gt; &amp;ndash; 512-byte logical sectors, physical sector
multiplier of 1. This is the sector size that Rockbox uses when reading the MBR and FAT
filesystem internally.&lt;/p&gt;
&lt;h3 id="rockboxs-usb-mode-uses-4096-byte-virtual-sectors"&gt;
Rockbox&amp;rsquo;s USB mode uses 4096-byte virtual sectors
&lt;a class="heading-link" href="#rockboxs-usb-mode-uses-4096-byte-virtual-sectors"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;When Rockbox presents the iPod as a USB mass storage device, it multiplies the sector size
by 8. This is configured in the iPod Classic&amp;rsquo;s target header (&lt;code&gt;ipod6g.h&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define DEFAULT_VIRT_SECTOR_SIZE 4096
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The USB stack calls &lt;code&gt;disk_set_sector_multiplier(8)&lt;/code&gt; before entering USB mode, making the
host see 4096-byte logical sectors. This is why &lt;code&gt;lsblk&lt;/code&gt; shows &lt;code&gt;LOG-SEC 4096&lt;/code&gt; when the iPod
is connected in normal Rockbox USB mode.&lt;/p&gt;
&lt;h3 id="linux-tools-respect-the-devices-reported-sector-size"&gt;
Linux tools respect the device&amp;rsquo;s reported sector size
&lt;a class="heading-link" href="#linux-tools-respect-the-devices-reported-sector-size"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;When you run &lt;code&gt;sfdisk&lt;/code&gt; or &lt;code&gt;fdisk&lt;/code&gt; on a device with 4096-byte logical sectors, the MBR
partition table entries are written in 4096-byte sector units. A partition starting at 1 MiB
is recorded as LBA sector 256 (256 * 4096 = 1,048,576 bytes).&lt;/p&gt;
&lt;p&gt;When you run &lt;code&gt;mkfs.vfat&lt;/code&gt; on that partition, it creates a FAT32 BPB with
&lt;code&gt;bytes_per_sector=4096&lt;/code&gt; to match the device.&lt;/p&gt;
&lt;h3 id="the-bootloader-reads-with-512-byte-sectors"&gt;
The bootloader reads with 512-byte sectors
&lt;a class="heading-link" href="#the-bootloader-reads-with-512-byte-sectors"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;When the iPod boots, it reads the MBR using its ATA driver at the native 512-byte sector
size. It sees LBA start value 256 and interprets it as byte offset 256 * 512 = 131,072 &amp;ndash;
not 1,048,576 where the partition actually starts.&lt;/p&gt;
&lt;p&gt;Rockbox has a multiplier loop that compensates for this by trying the LBA value multiplied
by 1, 2, 4, and 8. At 8x (256 * 8 = 2048, byte offset 2048 * 512 = 1,048,576), it finds
the correct location. But then it reads a BPB with &lt;code&gt;bytes_per_sector=4096&lt;/code&gt;, which creates
further complications in the FAT driver&amp;rsquo;s internal math. The mount fails.&lt;/p&gt;
&lt;h2 id="the-fix"&gt;
The fix
&lt;a class="heading-link" href="#the-fix"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;The key insight came from reading the bootloader source code more carefully. There are
actually &lt;strong&gt;two different USB modes&lt;/strong&gt; with different sector sizes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// bootloader/ipod-s5l87xx.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Voluntary USB mode (SELECT+RIGHT at boot):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;button_read_device&lt;/span&gt;() &lt;span style="color:#f92672"&gt;==&lt;/span&gt; (BUTTON_SELECT&lt;span style="color:#f92672"&gt;|&lt;/span&gt;BUTTON_RIGHT)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;disk_set_sector_multiplier&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;IF_MD&lt;/span&gt;(i,) DEFAULT_VIRT_SECTOR_SIZE&lt;span style="color:#f92672"&gt;/&lt;/span&gt;SECTOR_SIZE);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;usb_mode&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// host sees 4096-byte sectors
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Error USB mode (partition mount failed):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; ERR_RB:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;usb_mode&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// host sees 512-byte sectors! No multiplier set.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the bootloader enters USB mode due to a &amp;ldquo;No partition found&amp;rdquo; error, it does NOT set
the sector multiplier. The host sees the ATA-native 512-byte sectors.&lt;/p&gt;
&lt;p&gt;This means the fix is straightforward: &lt;strong&gt;format while in the bootloader&amp;rsquo;s error-mode USB&lt;/strong&gt;.
The bootloader is already in this mode when showing &amp;ldquo;No partition found&amp;rdquo; and waiting for a
USB connection. Simply:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Connect USB while the bootloader shows &amp;ldquo;No partition found&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Linux sees &lt;code&gt;/dev/sdX&lt;/code&gt; with 512-byte logical sectors&lt;/li&gt;
&lt;li&gt;Partition and format normally&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Wipe the first 1 MiB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dd &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/dev/zero of&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/dev/sdX bs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;512&lt;/span&gt; count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2048&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Create a single FAT32 LBA partition&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sfdisk --wipe always /dev/sdX &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;label: dos
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;unit: sectors
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/dev/sdX1 : start=2048, type=0c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Format with 32 KB clusters (Rockbox max is 128 KB)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkfs.vfat -F &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt; -s &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt; -n IPOD /dev/sdX1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Mount and install Rockbox&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mount /dev/sdX1 /mnt/ipod
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;unzip rockbox.zip -d /mnt/ipod
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;umount /mnt/ipod
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After disconnecting and rebooting (MENU+SELECT), Rockbox boots successfully:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MBR has 512-byte sector LBA values that the bootloader reads correctly&lt;/li&gt;
&lt;li&gt;FAT32 BPB has &lt;code&gt;bytes_per_sector=512&lt;/code&gt; that the FAT driver handles natively&lt;/li&gt;
&lt;li&gt;No multiplier tricks needed&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-tell-which-usb-mode-youre-in"&gt;
How to tell which USB mode you&amp;rsquo;re in
&lt;a class="heading-link" href="#how-to-tell-which-usb-mode-youre-in"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Check the logical sector size of the device:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /sys/block/sdX/queue/logical_block_size
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;512&lt;/strong&gt; &amp;ndash; you&amp;rsquo;re in bootloader error-mode USB (or a card reader). Safe to format.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;4096&lt;/strong&gt; &amp;ndash; you&amp;rsquo;re in Rockbox main firmware USB or voluntary bootloader USB. Do NOT
format from this mode. Reboot into the bootloader error mode first.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alternatively, &lt;code&gt;lsblk -o NAME,LOG-SEC,MODEL&lt;/code&gt; shows the sector size for all devices.&lt;/p&gt;
&lt;h2 id="other-things-i-learned-along-the-way"&gt;
Other things I learned along the way
&lt;a class="heading-link" href="#other-things-i-learned-along-the-way"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The iPod Classic doesn&amp;rsquo;t need a firmware partition.&lt;/strong&gt; Unlike older iPods (Video, Nano)
that store firmware on a dedicated disk partition, the iPod Classic 6G/7G stores its
firmware in NOR flash. A single FAT32 data partition is the correct layout.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The iFlash adapter identifies as &amp;ldquo;CompactFlash&amp;rdquo;, not &amp;ldquo;iPod&amp;rdquo;.&lt;/strong&gt; If you&amp;rsquo;re writing scripts
to auto-detect the device, match on the model string &amp;ldquo;CompactFlash&amp;rdquo;, not &amp;ldquo;iPod&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rockbox has a maximum cluster size of 128 KB.&lt;/strong&gt; On a 477 GiB partition with 512-byte
sectors, &lt;code&gt;mkfs.vfat&lt;/code&gt; will default to 128 sectors/cluster = 64 KB clusters. This is fine.
If you explicitly set &lt;code&gt;-s 64&lt;/code&gt; (32 KB clusters), that works too. Don&amp;rsquo;t go above &lt;code&gt;-s 256&lt;/code&gt;
(128 KB).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Most guides assume iTunes or Windows.&lt;/strong&gt; The standard advice for &amp;ldquo;No partition found&amp;rdquo; on
iPod Classic is &amp;ldquo;restore with iTunes.&amp;rdquo; iTunes creates a properly formatted disk because
Apple knows the correct parameters. If you&amp;rsquo;re on Linux without iTunes, you need to
understand the sector size situation yourself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Building Rockbox from source on Linux is straightforward.&lt;/strong&gt; The cross-compiler toolchain
builds non-interactively with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RBDEV_TARGET&lt;span style="color:#f92672"&gt;=&lt;/span&gt;a RBDEV_PREFIX&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/path/to/toolchain bash tools/rockboxdev.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then configure and build:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/path/to/toolchain/bin:&lt;/span&gt;$PATH&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;../tools/configure --target&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;29&lt;/span&gt; --type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;B &lt;span style="color:#75715e"&gt;# bootloader&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make -j&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;nproc&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;The bootloader is flashed via DFU, not written to disk.&lt;/strong&gt; Use &lt;code&gt;mks5lboot --bl-inst&lt;/code&gt; with
the iPod in DFU mode. The bootloader lives in NOR flash separately from the SD card, so
reformatting the SD card doesn&amp;rsquo;t affect it.&lt;/p&gt;
&lt;h2 id="summary"&gt;
Summary
&lt;a class="heading-link" href="#summary"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re getting &amp;ldquo;No partition found&amp;rdquo; on an iPod Classic with iFlash and Rockbox on Linux:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check the logical sector size with &lt;code&gt;cat /sys/block/sdX/queue/logical_block_size&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If it&amp;rsquo;s 4096, you&amp;rsquo;re in the wrong USB mode &amp;ndash; reboot into bootloader error mode&lt;/li&gt;
&lt;li&gt;If it&amp;rsquo;s 512, format with &lt;code&gt;sfdisk&lt;/code&gt; + &lt;code&gt;mkfs.vfat -F 32 -s 64&lt;/code&gt; and install Rockbox&lt;/li&gt;
&lt;li&gt;Reboot and enjoy your music&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>4-4-6-2 Meditation</title><link>https://kinbiko.com/posts/2025-12-01-4-4-6-2-meditation/</link><pubDate>Mon, 01 Dec 2025 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2025-12-01-4-4-6-2-meditation/</guid><description>&lt;p&gt;I recently discovered 4-4-6-2 breathing: 4 seconds in, 4 hold, 6 out, 2 hold.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s become my shortcut to calm down when I&amp;rsquo;m feeling stressed.
A few cycles and I&amp;rsquo;m noticeably more relaxed.&lt;/p&gt;
&lt;iframe width="560" height="315"
src="https://www.youtube.com/embed/CW_kC7lMLBA?loop=1&amp;playlist=CW_kC7lMLBA"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen&gt;
&lt;/iframe&gt;</description></item><item><title>Incidents and Blame</title><link>https://kinbiko.com/posts/2025-11-28-incidents-and-blame/</link><pubDate>Fri, 28 Nov 2025 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2025-11-28-incidents-and-blame/</guid><description>&lt;p&gt;I believe strongly that if an individual is to blame for a (production/security/operational) incident, then this individual should be fired.&lt;/p&gt;
&lt;p&gt;This is because I also strongly feel that the only acceptable time to blame an individual for an incident is in the case of intentional malicious action.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Any&lt;/strong&gt; other incident can trace the root cause to something systemic that could be improved.
For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bad hiring practices that put individuals in situations where they operate tools outside their skillset.&lt;/li&gt;
&lt;li&gt;Insufficient testing or testing environments.&lt;/li&gt;
&lt;li&gt;Poor documentation that leaves engineers guessing.&lt;/li&gt;
&lt;li&gt;Insufficient rollback mechanisms.&lt;/li&gt;
&lt;li&gt;Inadequate monitoring and alerting.&lt;/li&gt;
&lt;li&gt;Missing access controls.&lt;/li&gt;
&lt;li&gt;Bad onboarding and training programs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;m sure you can think of dozens more&amp;hellip;&lt;/p&gt;
&lt;p&gt;If you blame an employee for an incident then your culture sucks, and you should feel bad.
Worse than said employee does.&lt;/p&gt;</description></item><item><title>Managers and Incidents</title><link>https://kinbiko.com/posts/2025-11-26-managers-and-incidents/</link><pubDate>Wed, 26 Nov 2025 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2025-11-26-managers-and-incidents/</guid><description>&lt;p&gt;There are plenty of texts talking about expectations of engineers and best practices during an incident.
What&amp;rsquo;s not mentioned as often, mainly because giving feedback &amp;ldquo;up&amp;rdquo; is hard, is expectations of senior management.
In a recent discussion at work, I naively proposed the following 3 expectations / guidelines for senior managers and above.&lt;/p&gt;
&lt;h3 id="power-dynamics"&gt;
Power Dynamics
&lt;a class="heading-link" href="#power-dynamics"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;The voluntary involvement of senior management during an active incident is discouraged.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is due to how easily power-dynamics add rpessure and confusion in regards to authority when dealing with an already stressful situation.&lt;/p&gt;
&lt;h3 id="performance-evaluations"&gt;
Performance Evaluations
&lt;a class="heading-link" href="#performance-evaluations"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Being a leading actor in resolving an important production incident should be no more rewarded than quietly preventing one, and senior management should be conscious of this when doing performance evaluations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This point applies to organizations large enough to have systems and processes around internal career progression.&lt;/p&gt;
&lt;h3 id="adoption-non-reaction"&gt;
Adoption Non-Reaction
&lt;a class="heading-link" href="#adoption-non-reaction"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;If, as a result of a team adopting best practices around incident management increases visibility around its incidents, then senior management should not react with any more urgency than prior to adoption, keeping the level of trust, oversight and attention as it was previously.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is to not revert the adoption for said team, and to not dissuade other teams from adopting incident handling best practices.&lt;/p&gt;
&lt;h2 id="go-on"&gt;
Go on&amp;hellip;
&lt;a class="heading-link" href="#go-on"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m lucky enough to work with several engineering leaders I consider far senior to myself.&lt;/p&gt;
&lt;p&gt;A VP pointed out that the temptation for senior management to get closer to the action is fuelled by inadequate upwards communication.
Empathy goes both ways.&lt;/p&gt;
&lt;p&gt;A principal engineer also shared an idea for certain Directors/VPs to be trained as &amp;ldquo;Incident Executives&amp;rdquo;.
These are separate from &amp;ldquo;Incident Commander&amp;rdquo; (typically an individual contributor).
The role of an Incident Executive is to be present on calls and communicate with other execs as well as provide shielding for the incident response team.&lt;/p&gt;</description></item><item><title>Naive Musings on AI</title><link>https://kinbiko.com/posts/2025-11-25-naive-musings-on-ai/</link><pubDate>Tue, 25 Nov 2025 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2025-11-25-naive-musings-on-ai/</guid><description>&lt;p&gt;Let&amp;rsquo;s set aside the harmful impact AI has on artists (copyright), the environment (GPUs want electrons), and humanity (enforcing existing unfair systems) in general for a sec.
Let me share where I&amp;rsquo;ve personally extraxted the greatest value from AI.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t find that AI does &lt;strong&gt;my job&lt;/strong&gt; better than I do it.
That is, the job I&amp;rsquo;m personally an expert at.
For example, AI doesn&amp;rsquo;t write better Go code than me.
It can write code faster, and even after I&amp;rsquo;ve corrected it&amp;rsquo;s output (if it&amp;rsquo;s written using a very refined Claude task or agent), it is likely net faster than me in solving problems.
Although, I dislike the fact that AI does the &amp;ldquo;fun&amp;rdquo; part of my job faster than me&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://kinbiko.com/img/ai-dishes.png" alt="Newspaper quote from Joanna Maciejewska saying “I want AI to do my laundry and dishes so that I can do art and writing, not for AI to do my art and writing so that I can do my laundry and dishes.”"&gt;&lt;/p&gt;
&lt;p&gt;But what it &lt;em&gt;is&lt;/em&gt; better than me at, is producing text, in particular code, that I&amp;rsquo;m not an expert at.
For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LaTeX and Beamer, e.g. for presentations.&lt;/li&gt;
&lt;li&gt;Manim animation code in Python.&lt;/li&gt;
&lt;li&gt;Custom plugins in Lua for my neovim text editor.&lt;/li&gt;
&lt;li&gt;Templates and style sheets for my blog powered by Hugo.&lt;/li&gt;
&lt;li&gt;Writing native-sounding Japanese based on the equivalent English.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And more generally, I recognize now that it&amp;rsquo;s value is bringing the standard of everyone&amp;rsquo;s non-core text-producing skills up to a higher standard.&lt;/p&gt;</description></item><item><title>Writing More, Publishing More</title><link>https://kinbiko.com/posts/2025-08-19-writing-more-publishing-more/</link><pubDate>Tue, 19 Aug 2025 19:37:36 +0900</pubDate><guid>https://kinbiko.com/posts/2025-08-19-writing-more-publishing-more/</guid><description>&lt;p&gt;I want to write more.
And publish what I&amp;rsquo;m writing more, not worrying about meeting some high bar before publishing.&lt;/p&gt;
&lt;p&gt;For one, writing helps me think clearly.
Personally, I don&amp;rsquo;t &amp;ldquo;think&amp;rdquo; in words, but without turning my thoughts into words in some (human/computer) language I can&amp;rsquo;t communicate it to others.
And by converting the idea to a form others can understand, I also understand it better as a result.&lt;/p&gt;
&lt;p&gt;Secondly, writing moves my unfinished ideas out of my brain where they&amp;rsquo;re distracting me, into a location where I may forget about it and move on.
Unprocessed thoughts, e.g. because I&amp;rsquo;ve not felt like I&amp;rsquo;ve taken in news etc., are very distracting.
By taking 5 minutes to write down my thoughts, I can move on from the distracting thoughts.&lt;/p&gt;
&lt;p&gt;Thirdly, by choosing to publish what I&amp;rsquo;m writing, I&amp;rsquo;m hoping to attract more like-minded people.
It&amp;rsquo;s not easy to make new friends as adults (maybe even as kids these days)?
By publishing, I can share the way I&amp;rsquo;m thinking.
Maybe someone finds it interesting / vibe with what I&amp;rsquo;m saying.&lt;/p&gt;
&lt;p&gt;Finally, writing is a form of meditation. Espeically when it&amp;rsquo;s handwritten.
I find myself looking for reliable sources for entering a flow state.
Writing by hand, focusing on neat handwriting, works well.&lt;/p&gt;
&lt;p&gt;Who knows, if I manage to write enough, my voice can outlive me through AI&amp;hellip;&lt;/p&gt;
&lt;p&gt;But why would you want that?&lt;/p&gt;</description></item><item><title>How I Write Go</title><link>https://kinbiko.com/talks/2025-06-21-how-i-write-go/</link><pubDate>Sat, 21 Jun 2025 12:00:00 +0000</pubDate><guid>https://kinbiko.com/talks/2025-06-21-how-i-write-go/</guid><description>&lt;p&gt;Tips and tricks around writing Go after 8 years.&lt;/p&gt;</description></item><item><title>Go Workshop</title><link>https://kinbiko.com/talks/2025-06-21-go-workshop/</link><pubDate>Sat, 21 Jun 2025 00:00:00 +0000</pubDate><guid>https://kinbiko.com/talks/2025-06-21-go-workshop/</guid><description>&lt;p&gt;Beginner workshop introducing the syntax and key ideas of the Go programming language.&lt;/p&gt;</description></item><item><title>Docker Deep Dive</title><link>https://kinbiko.com/talks/2025-02-12-docker/</link><pubDate>Wed, 12 Feb 2025 00:00:00 +0000</pubDate><guid>https://kinbiko.com/talks/2025-02-12-docker/</guid><description>&lt;p&gt;This talk introduces Docker to beginners with lots of practical demos,
introduces best practices for experienced users,
and discusses the internals for advanced users.&lt;/p&gt;</description></item><item><title>Profitable Go Tests</title><link>https://kinbiko.com/talks/2024-09-19-profitable-go-tests/</link><pubDate>Thu, 19 Sep 2024 00:00:00 +0000</pubDate><guid>https://kinbiko.com/talks/2024-09-19-profitable-go-tests/</guid><description>&lt;p&gt;In this presentation I&amp;rsquo;m proposing a novel judgment method if a test is worth writing or not,
and provide several tips for how to write high-quality tests in Go.&lt;/p&gt;</description></item><item><title>Commandline Foo</title><link>https://kinbiko.com/talks/2024-09-07-commandline-foo/</link><pubDate>Sat, 07 Sep 2024 00:00:00 +0000</pubDate><guid>https://kinbiko.com/talks/2024-09-07-commandline-foo/</guid><description>&lt;p&gt;Some tips and tricks to make you love working on the command-line.&lt;/p&gt;</description></item><item><title>Cross Cultural Teams</title><link>https://kinbiko.com/talks/2024-05-18-cross-cultural-teams/</link><pubDate>Sat, 18 May 2024 00:00:00 +0000</pubDate><guid>https://kinbiko.com/talks/2024-05-18-cross-cultural-teams/</guid><description>&lt;p&gt;Co-presented with Chad Kohalyk, giving a short overview of Erin Meyer’s excellent book The Culture Map: Breaking Through the Invisible Boundaries of Global Business which lays out an 8-scale framework for analyzing business culture and developing strategies for an effective team.&lt;/p&gt;</description></item><item><title>Automating your CV</title><link>https://kinbiko.com/posts/2023-03-19-automate-your-cv/</link><pubDate>Sun, 19 Mar 2023 01:00:00 +0900</pubDate><guid>https://kinbiko.com/posts/2023-03-19-automate-your-cv/</guid><description>&lt;p&gt;I found that continuously updating my CV over time was a pain, so I simplified it and automated it.&lt;/p&gt;
&lt;p&gt;These days I use a simple CI workflow in a GitHub repository that generates a new &lt;code&gt;.pdf&lt;/code&gt; CV based on a Markdown source file.&lt;/p&gt;
&lt;p&gt;If you like the sound of this, I&amp;rsquo;ve &lt;a href="https://github.com/kinbiko/cv-template" class="external-link" target="_blank" rel="noopener"&gt;created a GitHub template&lt;/a&gt; for this pattern, should you wish to follow my example.&lt;/p&gt;
&lt;p&gt;The template contains placeholders to fit the structure I personally use these days, and is littered with tips and advice for how to write a good CV (I say this as someone who&amp;rsquo;s screened a lot of low-quality CVs).&lt;/p&gt;</description></item><item><title>Auto-merging Dependabot PRs</title><link>https://kinbiko.com/posts/2022-10-29-auto-merging-dependabot-prs/</link><pubDate>Sat, 29 Oct 2022 01:00:00 +0900</pubDate><guid>https://kinbiko.com/posts/2022-10-29-auto-merging-dependabot-prs/</guid><description>&lt;p&gt;Keeping your code&amp;rsquo;s dependencies up to date is hard, so luckily there are free tools like &lt;a href="https://github.blog/2020-06-01-keep-all-your-packages-up-to-date-with-dependabot/" class="external-link" target="_blank" rel="noopener"&gt;Dependabot&lt;/a&gt; around, that can create PRs against your repository whenever any of your dependencies have a more recent version updated.
Depending on the size of your codebase, this can turn into quite a chore as you have to verify that the dependencies don&amp;rsquo;t break your code.&lt;/p&gt;
&lt;p&gt;A common solution is to establish a thorough test suite and other CI checks that you trust to let you know if your code is broken and combine that with automatically merging Dependabot PRs.&lt;/p&gt;
&lt;p&gt;Unfortuately, the &lt;a href="https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions#enable-auto-merge-on-a-pull-request" class="external-link" target="_blank" rel="noopener"&gt;default instructions from GitHub&lt;/a&gt; for doing exactly this leave a little to be desired:&lt;/p&gt;
&lt;p&gt;They recommend creating a separate GitHub Actions workflow, like the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Dependabot auto-merge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;pull_request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;permissions&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;contents&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;write&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;pull-requests&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;write&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;jobs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;dependabot&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ubuntu-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${{ github.actor == &amp;#39;dependabot[bot]&amp;#39; }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;steps&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Dependabot metadata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;metadata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;dependabot/fetch-metadata@v1.1.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;github-token&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;${{ secrets.GITHUB_TOKEN }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Enable auto-merge for Dependabot PRs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${{contains(steps.metadata.outputs.dependency-names, &amp;#39;my-dependency&amp;#39;) &amp;amp;&amp;amp; steps.metadata.outputs.update-type == &amp;#39;version-update:semver-patch&amp;#39;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;gh pr merge --auto --merge &amp;#34;$PR_URL&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;env&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;PR_URL&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${{github.event.pull_request.html_url}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;GITHUB_TOKEN&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${{secrets.GITHUB_TOKEN}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you just apply this naively, patch version upgrade Dependabot PRs for a fictitious &lt;code&gt;my-dependency&lt;/code&gt; dependency will be merged automatically without waiting for any particular jobs (e.g. your tests) to finish.
That&amp;rsquo;s probably not what you want.&lt;/p&gt;
&lt;p&gt;Instead you probably want your standard CI jobs like testing and linting to pass first, and it&amp;rsquo;s more reasonable to expect those jobs to run on &lt;code&gt;push&lt;/code&gt; instead of &lt;code&gt;pull_request&lt;/code&gt; or &lt;code&gt;pull_request_target&lt;/code&gt;.
This becomes a problem since the steps mentioned need &lt;code&gt;pull_request&lt;/code&gt; or &lt;code&gt;pull_request_target&lt;/code&gt; events to work.&lt;/p&gt;
&lt;p&gt;After a lot of trial and error, I&amp;rsquo;ve come up with an alternative approach I prefer instead, and I&amp;rsquo;m sharing it here in case others can benefit from this as well:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;push&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;(...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;permissions&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;contents&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;write&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;pull-requests&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;write&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;jobs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Verify you can build the code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;build&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;(...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Run a linter against your code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;lint&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;(...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Run your tests against the code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;test&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;(...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Automatically merge if it&amp;#39;s a Dependabot PR that passes the build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;dependabot&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ubuntu-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Only run this job for dependabot PRs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;if&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${{ github.actor == &amp;#39;dependabot[bot]&amp;#39; }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Only run if the required checks pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;needs&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;test, lint, build]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;steps&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Check out code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;actions/checkout@v3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Auto-merge Dependabot PRs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Find the PR number based on the current branch name, and squash merge based on this number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;PR_NUM=&amp;#34;$(gh pr list | grep $(git branch --show-current) | cut -f1)&amp;#34;; gh pr merge --auto --squash $PR_NUM&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;env&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;GH_TOKEN&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${{secrets.GITHUB_TOKEN}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above will automatically merge your Dependabot PRs, and only your Dependabot PRs, if the build passes.
You may have noticed that I haven&amp;rsquo;t included the check that would only run this for only &lt;code&gt;patch&lt;/code&gt; updates &amp;ndash; that&amp;rsquo;s because I personally don&amp;rsquo;t want this check.
I leave adding this check as an exercise for the reader.&lt;/p&gt;
&lt;h2 id="important-note"&gt;
Important note
&lt;a class="heading-link" href="#important-note"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Do this only if you trust your dependencies. This automation makes you particularly vulnerable to supply-chain attacks.&lt;/p&gt;</description></item><item><title>(Go) Error messages should be boring</title><link>https://kinbiko.com/posts/2022-07-30-error-messages-should-be-boring/</link><pubDate>Sat, 30 Jul 2022 01:00:00 +0900</pubDate><guid>https://kinbiko.com/posts/2022-07-30-error-messages-should-be-boring/</guid><description>&lt;p&gt;When error messages contain &amp;ldquo;useful information&amp;rdquo; e.g. application-specific IDs or other variables then the error messages lose their &amp;ldquo;grepability&amp;rdquo;.
In other words, you cannot quickly search a codebase for an error without removing anything you believe could be variable.&lt;/p&gt;
&lt;p&gt;You might not think this is a big issue, and I might even agree with you there, but you might as well make it a practice to make error messages boring &amp;ndash; I.e. no variables in strings.&lt;/p&gt;
&lt;p&gt;To be clear I&amp;rsquo;m not talking about &lt;code&gt;fmt.Errorf(&amp;quot;could not foo the bar: %w&amp;quot;, err)&lt;/code&gt; which uses &lt;code&gt;fmt.Errorf&lt;/code&gt; to wrap an error using the &lt;code&gt;%w&lt;/code&gt; format directive.
I&amp;rsquo;m a proponent of wrapping errors.
What I think could be problematic is something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fmt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Errorf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;user %s cannot access account %s: %w&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;userID&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;accountID&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where &lt;code&gt;userID&lt;/code&gt; and &lt;code&gt;accountID&lt;/code&gt; would likely differ between each time the error is generated.
I argue this makes errors difficult to search for in a code base and it could even mess with your error reporting tools like Sentry.
Error reporting tools often group &amp;ldquo;Events&amp;rdquo; of the same &amp;ldquo;Issue&amp;rdquo; (Sentry) / &amp;ldquo;Error&amp;rdquo; (Bugsnag) based on the attached stacktrace.
Now, Go in particular doesn&amp;rsquo;t provide stacktraces in errors by default, so error reporting tools fall back on the error &lt;em&gt;message&lt;/em&gt; for grouping events.
If the error message is different because we include request- or goroutine specific data then events aren&amp;rsquo;t grouped together.
A potential consequence of this is spammy notifications which in turn could lead to ignoring notifications and alerting from these tools altogether.
I&amp;rsquo;m sadly speaking from experience here&amp;hellip;&lt;/p&gt;
&lt;p&gt;The solution I&amp;rsquo;m proposing is to follow the same pattern that structured logging libraries like &lt;a href="https://github.com/uber-go/zap" class="external-link" target="_blank" rel="noopener"&gt;Zap&lt;/a&gt; or &lt;a href="https://github.com/sirupsen/logrus" class="external-link" target="_blank" rel="noopener"&gt;Logrus&lt;/a&gt; follow:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Include IDs etc. as part of metadata (&amp;ldquo;fields&amp;rdquo;) instead of in the message itself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This does mean we need an &lt;code&gt;error&lt;/code&gt; type that supports this metadata functionality.
It&amp;rsquo;s not too hard to create yourself, and if you&amp;rsquo;re curious to see what this would look like, take a look at &lt;a href="https://github.com/kinbiko/rogerr" class="external-link" target="_blank" rel="noopener"&gt;&lt;code&gt;github.com/kinbiko/rogerr&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The pattern I&amp;rsquo;m proposing in this package is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attach metadata (e.g. user ID) to a &lt;code&gt;context.Context&lt;/code&gt; variable with &lt;code&gt;ctx = rogerr.WithMetadatum(ctx, &amp;quot;user_id&amp;quot;, userID)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;When you need to create an error, use &lt;code&gt;err = rogerr.Wrap(ctx, err, &amp;quot;unable to foo the bar&amp;quot;)&lt;/code&gt; to attach the metadata to an &lt;code&gt;error&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When you log/report/otherwise handle the error use &lt;code&gt;md := rogerr.Metadata(err)&lt;/code&gt; to get a &lt;code&gt;map[string]interface{}&lt;/code&gt; of all metadata fields associated with the error.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://pkg.go.dev/github.com/kinbiko/rogerr#example-Wrap" class="external-link" target="_blank" rel="noopener"&gt;Full example found here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once you have this metadata, you can then attach as fields to a structured log message or as &lt;code&gt;tags&lt;/code&gt; in a report to Sentry, etc. You could even execute custom error handling logic based off the values in this map should you wish, all while maintaining grepability of your error messages.&lt;/p&gt;</description></item><item><title>Rewriting my Neovim .vimrc in Lua</title><link>https://kinbiko.com/posts/2021-08-23-rewriting-vimrc-in-lua/</link><pubDate>Mon, 23 Aug 2021 23:00:00 +0900</pubDate><guid>https://kinbiko.com/posts/2021-08-23-rewriting-vimrc-in-lua/</guid><description>&lt;p&gt;I recently rewrote my Neovim configuration in Lua in order to take advantage of a more intuitive programming language for configuration, Lua-only plugins, and powerful Neovim-only features such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The built in LSP: Language Server Protocol, IDE features like &amp;ldquo;show docs&amp;rdquo;, &amp;ldquo;find references&amp;rdquo;, &amp;ldquo;rename&amp;rdquo;, and &amp;ldquo;go to definition&amp;rdquo; for basically any language.&lt;/li&gt;
&lt;li&gt;Treesitter: Powerful parsing of any programming language, which means plugins and syntax highlighting can make powerful and accurate transformations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this article I&amp;rsquo;d like to share some tips from my experience rewriting my config (tl;dr: &lt;a href="https://github.com/kinbiko/dotfiles/commit/bfeb69e6cd54a3b7e947fe734e416ab7acfa7a8c" class="external-link" target="_blank" rel="noopener"&gt;check this commit to see what changed&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id="this-article-pales-in-comparison"&gt;
This article pales in comparison
&lt;a class="heading-link" href="#this-article-pales-in-comparison"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Most of what I&amp;rsquo;ve learned I&amp;rsquo;ve learned from &lt;a href="https://github.com/nanotee/nvim-lua-guide" class="external-link" target="_blank" rel="noopener"&gt;this GitHub repository&lt;/a&gt;, which is a lot more in-depth than this article.&lt;/p&gt;
&lt;h2 id="lua-primer"&gt;
Lua primer
&lt;a class="heading-link" href="#lua-primer"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Lua, at least the kind of Lua you&amp;rsquo;re likely to use for writing your Vim config, is really intuitive and easy to learn, assuming you already know an interpreted programming language like JavaScript.
Here are the least intutive bits, the rest you can probably figure out when you first see it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Single line comments are &lt;code&gt;--&lt;/code&gt;. Multi line comments are &lt;code&gt;--[[commented stuff in here]]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Variables are global by default. Use &lt;code&gt;local myVar = 'foobar'&lt;/code&gt; whenever you declare a variable and you&amp;rsquo;re unlikely to run into trouble.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Table&amp;rdquo; is the central type, which acts as &amp;ldquo;object&amp;rdquo;, &amp;ldquo;map&amp;rdquo;, and &amp;ldquo;array&amp;rdquo;, all in one:
&lt;ul&gt;
&lt;li&gt;Map: &lt;code&gt;{foo = &amp;quot;bar&amp;quot;, baz = &amp;quot;bat&amp;quot;}&lt;/code&gt;; like JSON, but &lt;code&gt;=&lt;/code&gt; instead of &lt;code&gt;:&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Array: &lt;code&gt;local arr = {'foo', 'bar', 'baz',}&lt;/code&gt;; trailing commas are OK. Arrays are tables where the key is the index implicitly. Lua is 1-indexed. I.e. &lt;code&gt;arr[2] == bar -- true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Object: &lt;code&gt;local M = {}&lt;/code&gt; is typical when creating an object whose intent is to be used in other files. Add methods with &lt;code&gt;local function M:myMethod(arg) print(arg) end&lt;/code&gt; to add a &lt;code&gt;myMethod&lt;/code&gt; method to &lt;code&gt;M&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Import modules (files) with &lt;code&gt;local p = require('module.path')&lt;/code&gt;. The value returned from &lt;code&gt;module/path.lua&lt;/code&gt; is stored in &lt;code&gt;p&lt;/code&gt;. &lt;code&gt;require&lt;/code&gt; caches the returned value, so future calls to &lt;code&gt;require('module.path')&lt;/code&gt; will return the same value.&lt;/li&gt;
&lt;li&gt;Parentheses when calling functions with only one argument are optional. This means you sometimes see weird code like &lt;code&gt;require'somemodule'.method{foo='bar'}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;String concatenation uses the &lt;code&gt;..&lt;/code&gt; infix operator.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;d like a more accurate and less rambly introduction to Lua, check out this talk by TJ Devries (Neovim core contributor):&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/IP3J56sKtn0?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="store-your-configuration-in-git"&gt;
Store your configuration in Git
&lt;a class="heading-link" href="#store-your-configuration-in-git"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;You will mess up.
Store your vim config in Git upfront so you can increment on your migration process, and always return to a known state &amp;ndash; or even go back to VimL if Lua isn&amp;rsquo;t for you.&lt;/p&gt;
&lt;p&gt;You can find &lt;a href="https://github.com/kinbiko/dotfiles" class="external-link" target="_blank" rel="noopener"&gt;my (embarrassing) evolution of Vim usage on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="start-with-structure-before-refactoring"&gt;
Start with structure before refactoring
&lt;a class="heading-link" href="#start-with-structure-before-refactoring"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Start the migration by putting files in their correct location without really rewriting anything.
Unless you&amp;rsquo;ve set the &lt;code&gt;$XDG_CONFIG_HOME&lt;/code&gt; variable to something other than &lt;code&gt;~/.config&lt;/code&gt;, you should make the following change:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-diff" data-lang="diff"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;- ~/.config/nvim/init.vim
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;+ ~/.config/nvim/init.lua
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then take the contents of your old &lt;code&gt;.vimrc&lt;/code&gt; and wrap them inside&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-lua" data-lang="lua"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim.cmd(&lt;span style="color:#e6db74"&gt;[[
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;lt;contents of .vimrc goes here&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;]]&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In Lua, &lt;code&gt;[[&lt;/code&gt; and &lt;code&gt;]]&lt;/code&gt; enclose a multi-line string, so you&amp;rsquo;ve probably guessed that the above code just evaluates the string (your old VimL config) as VimL.
This will most likely work out of the box.
Indeed, if you struggle to find the native Lua API for the change you want to do, you can call &lt;code&gt;vim.cmd('&amp;lt;some snippet&amp;gt;')&lt;/code&gt; at any time.
Commit now, and you&amp;rsquo;ll have a lot smaller and more obvious commits going forward.&lt;/p&gt;
&lt;h2 id="switch-to-a-lua-native-package-manager"&gt;
Switch to a Lua-native package manager
&lt;a class="heading-link" href="#switch-to-a-lua-native-package-manager"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I switched from (the excellent) &lt;a href="https://github.com/junegunn/vim-plug" class="external-link" target="_blank" rel="noopener"&gt;vim-plug&lt;/a&gt; to &lt;a href="https://github.com/wbthomason/packer.nvim" class="external-link" target="_blank" rel="noopener"&gt;packer&lt;/a&gt;, which lets me use Lua to define the dependencies, run Lua functions on updates or install.&lt;/p&gt;
&lt;p&gt;Packer also supports bootstrapping itself, and provides a snippet in its README in order to do just that.&lt;/p&gt;
&lt;p&gt;Recommendation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Don&amp;rsquo;t mess around with &lt;code&gt;:PackerCompile&lt;/code&gt; or &lt;code&gt;:PackerSync&lt;/code&gt; unless you really struggle with startup time. They can confuse matters really easily.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="rewrite-bit-by-bit-then-commit"&gt;
Rewrite bit by bit, then commit
&lt;a class="heading-link" href="#rewrite-bit-by-bit-then-commit"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I took the following approach to the migration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start by rewriting all my plugins to use &lt;code&gt;packer&lt;/code&gt;, googling and fixing things as I went along.&lt;/li&gt;
&lt;li&gt;Then I moved on to rewriting my &amp;lsquo;general&amp;rsquo; settings, basically the settings that were &lt;code&gt;set something=someVal&lt;/code&gt; in VimL.&lt;/li&gt;
&lt;li&gt;Then I moved on to mappings.&lt;/li&gt;
&lt;li&gt;Then I rewrote my &lt;code&gt;after/ftplugin/{lang}.lua&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;Then I added LSP client configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Key points:&lt;/p&gt;
&lt;p&gt;Interacting with the Neovim application will happen via the &lt;code&gt;vim&lt;/code&gt; global variable.&lt;/p&gt;
&lt;h3 id="options"&gt;
Options
&lt;a class="heading-link" href="#options"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vim.g.my_option = &amp;quot;my value&amp;quot;&lt;/code&gt; for setting global vim options.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vim.o.my_option = &amp;quot;my value&amp;quot;&lt;/code&gt; for setting other options.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vim.bo.my_option = &amp;quot;my value&amp;quot;&lt;/code&gt; for setting buffer-specific options.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vim.wo.my_option = &amp;quot;my value&amp;quot;&lt;/code&gt; for setting window-specific options.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;re not sure if an option is &lt;code&gt;buffer&lt;/code&gt; or &lt;code&gt;window&lt;/code&gt; just try setting it to one.
It will usually tell you if it&amp;rsquo;s wrong if you try and run it.&lt;/p&gt;
&lt;h3 id="mappings"&gt;
Mappings
&lt;a class="heading-link" href="#mappings"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;vim.api.nvim_set_keymap(kind, lhs, rhs, options)&lt;/code&gt; is the API that Neovim exposes for defining custom key-mappings, but this is a bit long-winded, so I recommend creating a utility function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-lua" data-lang="lua"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;local&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;map&lt;/span&gt;(kind, lhs, rhs, opts)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; vim.api.nvim_set_keymap(kind, lhs, rhs, opts)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here &lt;code&gt;kind&lt;/code&gt; can be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;''&lt;/code&gt;: The equivalent of &lt;code&gt;(nore)map&lt;/code&gt; in VimL, i.e. the mapping applies in visual, normal, select, and operator-pending modes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;n&lt;/code&gt;: Normal mode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v&lt;/code&gt;: Visual mode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i&lt;/code&gt;: Insert mode,&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;nore&lt;/code&gt; part of &lt;code&gt;nnoremap&lt;/code&gt;, &lt;code&gt;inoremap&lt;/code&gt; in VimL is configured as part of an option: &lt;code&gt;noremap = true&lt;/code&gt;.
I reckon most of your bindings will have &lt;code&gt;{ noremap = true, silent = true }&lt;/code&gt;, so you might as well assign this table to a variable pass it in to your mappings.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a snippet from my config where I&amp;rsquo;m taking advantage of the above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-lua" data-lang="lua"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;local&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;map&lt;/span&gt;(kind, lhs, rhs, opts)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; vim.api.nvim_set_keymap(kind, lhs, rhs, opts)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;local&lt;/span&gt; silentnoremap &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {noremap &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;, silent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Intuitive increment and decrement&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;map(&lt;span style="color:#e6db74"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;+&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;c-a&amp;gt;&amp;#39;&lt;/span&gt;, silentnoremap)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;map(&lt;span style="color:#e6db74"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;c-x&amp;gt;&amp;#39;&lt;/span&gt;, silentnoremap)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Conveniently enter command mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Don&amp;#39;t use silent=true as this removes the command line.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;map(&lt;span style="color:#e6db74"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;;&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;, {noremap&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Go to definition and pop back up&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Don&amp;#39;t do noremap to allow accessing LSP behaviour&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;map(&lt;span style="color:#e6db74"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;right&amp;gt;&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;gd&amp;#39;&lt;/span&gt;, { silent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;map(&lt;span style="color:#e6db74"&gt;&amp;#39;n&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;left&amp;gt;&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;c-t&amp;gt;&amp;#39;&lt;/span&gt;, { silent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="set-up-lsp"&gt;
Set up LSP
&lt;a class="heading-link" href="#set-up-lsp"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Setting up the native LSP client will largely depend on your own preferences, and the languages you write.
That said, I recommend using the following (Packer) plugins:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-lua" data-lang="lua"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;use &lt;span style="color:#e6db74"&gt;&amp;#39;neovim/nvim-lspconfig&amp;#39;&lt;/span&gt; &lt;span style="color:#75715e"&gt;-- Easy LSP configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;use &lt;span style="color:#e6db74"&gt;&amp;#39;kabouzeid/nvim-lspinstall&amp;#39;&lt;/span&gt; &lt;span style="color:#75715e"&gt;-- Install LSP servers on demand with :LSPInstall &amp;lt;name_of_language&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then configure them according to their instructions.
You&amp;rsquo;ll likely end up with other plugins that also want to integrate with LSP (e.g. &lt;a href="https://github.com/nvim-telescope/telescope.nvim" class="external-link" target="_blank" rel="noopener"&gt;Telescope&lt;/a&gt;), so your configuration will definitely look different to mine, but &lt;a href="https://github.com/kinbiko/dotfiles/blob/39538dfd28e5cdb366df5a7c35c446a55e90cbf7/config/nvim/lua/kinbiko/lsp.lua" class="external-link" target="_blank" rel="noopener"&gt;here it is regardless&lt;/a&gt;, with the hope that it can be useful as a reference, if nothing else.&lt;/p&gt;
&lt;h2 id="create-your-own-namespace-to-avoid-collisions"&gt;
Create your own namespace to avoid collisions
&lt;a class="heading-link" href="#create-your-own-namespace-to-avoid-collisions"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;It is of course up to you if you want to keep your entire configuration in a single &lt;code&gt;init.lua&lt;/code&gt; file, or if you want to spread your code across multiple files, but you have to be careful when organising files other than &lt;code&gt;init.lua&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;To avoid namespace collisions, don&amp;rsquo;t put your files directly under &lt;code&gt;~/.config/nvim/lua/foo.lua&lt;/code&gt;, but instead create another directory, named something that won&amp;rsquo;t collide with the dependencies/plugins that you use, such as using your GitHub username: &lt;code&gt;~/.config/nvim/lua/kinbiko/foo.lua&lt;/code&gt;.
This way you can create files with configuration and mappings per plugin, should you so wish, without having worry about &lt;code&gt;require&lt;/code&gt;ing the wrong thing.&lt;/p&gt;</description></item><item><title>How Iota works in Go</title><link>https://kinbiko.com/posts/2021-03-08-iota/</link><pubDate>Mon, 08 Mar 2021 18:00:00 +0900</pubDate><guid>https://kinbiko.com/posts/2021-03-08-iota/</guid><description>&lt;p&gt;Have you ever wondered how &lt;code&gt;iota&lt;/code&gt; works in Go?&lt;/p&gt;
&lt;p&gt;Basically, iota is the &lt;strong&gt;index&lt;/strong&gt; of the constant inside a multi-constant (&lt;code&gt;const (...)&lt;/code&gt;) declaration.
So the value of &lt;code&gt;iota&lt;/code&gt; for the first constant is &lt;code&gt;0&lt;/code&gt;, the second constant is &lt;code&gt;1&lt;/code&gt;, and so on.
This only works for constants, not &lt;code&gt;var&lt;/code&gt;s.&lt;/p&gt;
&lt;p&gt;This is probably best explained with an example.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;day&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Start counting days from 1, so ignore 0.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;day&lt;/span&gt; = &lt;span style="color:#66d9ef"&gt;iota&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// evaluates to the same as the RHS of the previous expression,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// which is iota,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// which is the index of this const expression in this const block,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// which is 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;monday&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// this time the index is 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;tuesday&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// etc.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;wednesday&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;thursday&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;friday&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;saturday&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sunday&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;String&lt;/span&gt;() &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;days&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; []&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Monday&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Tuesday&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Wednesday&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Thursday&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Friday&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Saturday&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Sunday&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;days&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Let&amp;#39;s do some wat maths. Waths if you will.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Test your understanding by guessing the answers:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printDay&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;monday&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tuesday&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printDay&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;sunday&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;wednesday&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printDay&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;tuesday&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;wednesday&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printDay&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;saturday&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tuesday&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printDay&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;sunday&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;wednesday&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printDay&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;friday&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;thursday&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;printDay&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;sunday&lt;/span&gt; ^ &lt;span style="color:#a6e22e"&gt;thursday&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;printDay&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fmt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Println&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can &lt;a href="https://play.golang.org/p/SbwZHDNZZp-" class="external-link" target="_blank" rel="noopener"&gt;run the above code in a Go Playground&lt;/a&gt; if you want to check your answers.&lt;/p&gt;</description></item><item><title>Hiding Directories in Finder</title><link>https://kinbiko.com/posts/2021-03-07-hiding-directories-in-finder/</link><pubDate>Sun, 07 Mar 2021 18:00:00 +0900</pubDate><guid>https://kinbiko.com/posts/2021-03-07-hiding-directories-in-finder/</guid><description>&lt;p&gt;You might know that prefixing a file or a directory with &lt;code&gt;.&lt;/code&gt; makes it &amp;lsquo;hidden&amp;rsquo; in unix-based systems &amp;ndash; i.e. they won&amp;rsquo;t show up when you run &lt;code&gt;ls&lt;/code&gt; and they won&amp;rsquo;t show up in your file browser (e.g. Finder).&lt;/p&gt;
&lt;p&gt;However, did you know that MacOS lets you hide any directory in Finder &amp;ndash; even if it&amp;rsquo;s not &lt;code&gt;.hidden&lt;/code&gt; &amp;ndash; using &lt;code&gt;chflags&lt;/code&gt;?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ chflags hidden dir1 dir2 dir3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I use the above to hide directories in my home directory, that I can&amp;rsquo;t remove (MacOS regenerates them automatically):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chflags hidden Applications Movies Music Pictures Public
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This saves me from context switching and searching for the directory or file that I want whenever I open my home directory.&lt;/p&gt;
&lt;p&gt;Note: &lt;code&gt;chflags hidden&lt;/code&gt; doesn&amp;rsquo;t &lt;strong&gt;remove&lt;/strong&gt; the directories, only hides them in Finder.
They are still visible with &lt;code&gt;ls&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Testing Tips for Intermediate Gophers: Coverage</title><link>https://kinbiko.com/posts/2021-01-17-go-test-coverage/</link><pubDate>Sun, 17 Jan 2021 18:00:00 +0900</pubDate><guid>https://kinbiko.com/posts/2021-01-17-go-test-coverage/</guid><description>&lt;p&gt;This article will cover how to get visibility of your test coverage in Go.
If you&amp;rsquo;re not comfortable with the basics of testing in Go, please checkout &lt;a href="../2020-02-22-testing-tips-for-beginner-gophers" &gt;my earlier article aimed at beginners&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="test-coverage"&gt;
Test coverage
&lt;a class="heading-link" href="#test-coverage"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Test coverage gives you a high-level overview you how much of your production code was invoked in your tests (e.g. as a percentage), but it can also give you a lower-level view of exactly which lines are invoked or missed.
Before we dive deeper into the &amp;lsquo;how&amp;rsquo;, let&amp;rsquo;s make sure we understand &lt;em&gt;why&lt;/em&gt; we care about test coverage.
Test coverage is a &lt;strong&gt;terrible&lt;/strong&gt; metric for evaluating the quality of your tests.
Repeat after me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;High test coverage does not imply high-quality tests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="so-whats-the-purpose-of-test-coverage-then"&gt;
So what&amp;rsquo;s the purpose of test coverage then?
&lt;a class="heading-link" href="#so-whats-the-purpose-of-test-coverage-then"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;In my opinion, test coverage serves two purposes:&lt;/p&gt;
&lt;p&gt;Firstly, it lets you quickly identify which lines have not been hit by tests.
This could indicate that your tests aren&amp;rsquo;t comprehensive enough: &amp;ldquo;Oops, this &lt;code&gt;if&lt;/code&gt; statement wasn&amp;rsquo;t tested, but it should have been. Let&amp;rsquo;s add another test&amp;rdquo;.
However, it could also identify impossible paths in your code: &amp;ldquo;We&amp;rsquo;ve already validated this value elsewhere so this can never happen&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Moreover, paired with a good Continuous Integration setup, you can identify if a change will remove tests prematurely, by warning you when the coverage of your pull request is lower than the base branch.&lt;/p&gt;
&lt;h3 id="how-to-report-test-coverage-in-go"&gt;
How to report test coverage in Go
&lt;a class="heading-link" href="#how-to-report-test-coverage-in-go"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;go&lt;/code&gt; tool supplies us with all the tools we need; no third-party solution required:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Write a &amp;#34;coverprofile&amp;#34; to a filed called coverage.out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test -coverprofile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;coverage.out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Invoke the &amp;#39;cover&amp;#39; go tool, and ask it to render the coverprofile file as HTML.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# This should open your default web browser.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go tool cover -html&lt;span style="color:#f92672"&gt;=&lt;/span&gt;coverage.out
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This shows you exactly how much of each production file was covered, and renders your source code in green if the particular line was covered by the tests, and red otherwise.
Type definitions, comments, and other &amp;ldquo;non-runnable&amp;rdquo; code are greyed out, as it doesn&amp;rsquo;t make sense to count these lines as part of our coverage.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://kinbiko.com/img/html-coverage.png" alt="Screenshot of coverage rendered as HTML"&gt;&lt;/p&gt;
&lt;p&gt;You can also see a report of your coverage report on a per-function basis:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Running coverage against github.com/kinbiko/bugsnag and requesting
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# per-function output
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ go test -coverprofile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;coverage.out github.com/kinbiko/bugsnag &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go tool cover -func&lt;span style="color:#f92672"&gt;=&lt;/span&gt;coverage.out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ok github.com/kinbiko/bugsnag 0.159s coverage: 87.5% of statements
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/configuration.go:67: validURL 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/configuration.go:75: populateDefaults 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/configuration.go:92: validate 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/configuration.go:124: makeRuntimeConstants 54.5%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:21: Serialize 60.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:39: Deserialize 55.6%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:86: val 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:127: WithBreadcrumb 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:143: makeBreadcrumbs 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:180: WithUser 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:196: WithBugsnagContext 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:213: WithMetadatum 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:226: WithMetadata 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:243: Metadata 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:251: initializeMetadataTab 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:301: updateFromCtx 38.9%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/context.go:332: getAttachedContextData 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/error.go:32: Error 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/error.go:47: Unwrap 66.7%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/error.go:61: Wrap 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/error.go:70: Wrap 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/error.go:84: makeStacktrace 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/error.go:120: makeModulePath 66.7%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:44: New 85.7%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:72: Close 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:93: Notify 75.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:129: loop 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:149: shutdown 70.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:172: makeReport 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:197: sendErrorReport 85.7%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:221: makeUnhandled 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:234: makeSeverity 83.3%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:246: severityReasonType 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:265: makeExceptions 82.4%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:297: makeJSONApp 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:306: makeJSONDevice 75.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:321: memStats 84.6%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:345: osVersion 66.7%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:352: makeNotifier 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:360: extractLowestBugsnagError 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/notifier.go:374: guard 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/session.go:30: StartSession 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/session.go:45: flushSessions 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/session.go:57: publishSessions 82.4%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/session.go:102: makeJSONSession 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/session.go:116: makeJSONSessionReport 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github.com/kinbiko/bugsnag/session.go:135: uuidv4 100.0%
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total: (statements) 87.5%
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="a-note-on-covermode-and-concurrent-programs"&gt;
A note on &lt;code&gt;covermode&lt;/code&gt; and concurrent programs
&lt;a class="heading-link" href="#a-note-on-covermode-and-concurrent-programs"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;go test&lt;/code&gt; has a parameter called &lt;code&gt;covermode&lt;/code&gt; which tweaks how the Go tool should think about &amp;ldquo;covering a line&amp;rdquo;.
Basically your options are &amp;ldquo;lines are either missed or hit&amp;rdquo; or &amp;ldquo;let&amp;rsquo;s count how many times a line is hit&amp;rdquo;.
The former is used by default, and is the least expensive.
You can get more of a &amp;lsquo;heatmap&amp;rsquo; feature (in the rendered HTML) by setting the &lt;code&gt;-covermode=count&lt;/code&gt;, however I recommend taking things a step further to avoid headaches.
Namely, use &lt;code&gt;-covermode=atomic&lt;/code&gt; to ensure that the lines hit are counted accurately even in concurrent programs.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ go test -coverprofile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;coverage.out -covermode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;atomic
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is significantly more expensive, but for most project the additional compute resource is surely negligible.&lt;/p&gt;</description></item><item><title>Function Types in Go</title><link>https://kinbiko.com/posts/2021-01-10-function-types-in-go/</link><pubDate>Sun, 10 Jan 2021 02:07:07 +0900</pubDate><guid>https://kinbiko.com/posts/2021-01-10-function-types-in-go/</guid><description>&lt;p&gt;A while ago, I saw a question in a Go developer Slack channel that went something like this (translated):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When would you want to define a function type like &lt;code&gt;type MyFunc func(msg string) error&lt;/code&gt;? Do you have any examples?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I replied with a &lt;code&gt;http.HandlerFunc&lt;/code&gt; example (more on that below), but there were many developers smarter than me in that Slack channel, and I ended up learning a lot from the other answers to this question.
This article will cover what I took away from the ensuing discussion.&lt;/p&gt;
&lt;h2 id="type-definitions"&gt;
Type definitions
&lt;a class="heading-link" href="#type-definitions"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s start off by talking about what the &lt;code&gt;type&lt;/code&gt; keyword does.
The most common type definitions usually look something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyStruct&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Fields...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the case of a struct, or in the case of an interface it might look something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyDependency&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;DoSomething&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;context&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Context&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I daresay more than 90% of the types I define look like the above.
However, you may create a type to identify a function signature as well, as defined in the original question.
To better understand when we might want to create such a type, let&amp;rsquo;s have a look at the spec for inspiration.
Among other things, &lt;a href="https://golang.org/ref/spec#Type_definitions" class="external-link" target="_blank" rel="noopener"&gt;the spec has the following to say about type definitions:&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A type definition creates a new, distinct type with the same underlying type and operations as the given type, and binds an identifier to it.
The new type is called a defined type.
It is different from any other type, including the type it is created from.
&lt;strong&gt;A defined type may have methods associated with it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The last sentence is key. Let&amp;rsquo;s see why!&lt;/p&gt;
&lt;h3 id="the-elegance-of-httphandlerfunc"&gt;
The elegance of &lt;code&gt;http.HandlerFunc&lt;/code&gt;
&lt;a class="heading-link" href="#the-elegance-of-httphandlerfunc"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Chances are you&amp;rsquo;ve played around with the &lt;code&gt;net/http&lt;/code&gt; package at least once when learning Go.
You may remember that many of the functions in &lt;code&gt;net/http&lt;/code&gt; revolve around a type called &lt;code&gt;http.Handler&lt;/code&gt;.
&lt;code&gt;http.Handler&lt;/code&gt; is a single-method interface:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Handler&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ServeHTTP&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ResponseWriter&lt;/span&gt;, &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Request&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It may be tempting to believe that you have to create your own struct that implements the &lt;code&gt;ServeHTTP&lt;/code&gt; method, but the &lt;code&gt;net/http&lt;/code&gt; provides a very convenient shortcut for us:
&lt;strong&gt;Whenever you need a http.Handler you can write a http.HandlerFunc&lt;/strong&gt; instead.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HandlerFunc&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ResponseWriter&lt;/span&gt;, &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Request&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works because &lt;strong&gt;the HandlerFunc type implements Handler&lt;/strong&gt;.
In other words, the &lt;strong&gt;HandlerFunc has a &lt;code&gt;ServeHTTP(ResponseWriter, *Request)&lt;/code&gt; method&lt;/strong&gt;.
The &lt;a href="https://go.googlesource.com/go/&amp;#43;/go1.15.6/src/net/http/server.go#2041" class="external-link" target="_blank" rel="noopener"&gt;implementation of this method invokes itself&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;f&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HandlerFunc&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;ServeHTTP&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ResponseWriter&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;f&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that we have an appreciation of how the &lt;code&gt;net/http&lt;/code&gt; package works, we can generalise this pattern further:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I can improve my package&amp;rsquo;s developer experience by defining a &lt;code&gt;Func&lt;/code&gt; type that implements a key single-method interface in my package.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can imagine this pattern being useful where a maintainer of a package regrets requiring an interface (where a function would do), but also doesn&amp;rsquo;t want to break backwards compatibility.&lt;/p&gt;
&lt;h3 id="function-types-as-lightweight-interfaces"&gt;
Function types as lightweight interfaces
&lt;a class="heading-link" href="#function-types-as-lightweight-interfaces"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;I think a lot of us has ingrained the pattern of requesting interfaces when constructing a new type.
This pattern scales well and is good practice in general, but as hinted to above there are cases where interfaces are overkill.
In this case, requesting a function might be a good solution.
By naming your function signature (by defining a function type) you avoid excessively long function signatures just like you would with interfaces.
Moreover, your users don&amp;rsquo;t have to cast their function definitions like you do have to in the case of defining &lt;code&gt;http.HandlerFunc&lt;/code&gt;s:&lt;/p&gt;
&lt;p&gt;After reflecting on this pattern I decided to change some interfaces into function types in a package I wrote.
The &lt;a href="https://github.com/kinbiko/bugsnag/commit/a41644d01cf73458b579c0f225c740cd91502d96" class="external-link" target="_blank" rel="noopener"&gt;diff of this change&lt;/a&gt; may be more illustrative than what I can write in words in this blog post.
Note that this &lt;em&gt;is a breaking change&lt;/em&gt;, but the change required by users of your package are trivial in most cases.
To see why, remember that methods are functions too &amp;ndash; and as such they can adhere to function type definitions.
Where users previously passed in an implementation of an interface, they now have to pass in the function of that implementation.
I.e. changing &lt;code&gt;someDep&lt;/code&gt; to &lt;code&gt;someDep.FuncImplementation&lt;/code&gt; when invoking your package&amp;rsquo;s function.
In fact &amp;ndash; your users are now free to rename this function (or even make it private)!&lt;/p&gt;
&lt;h3 id="use-function-definitions-to-create-default-arguments"&gt;
Use function definitions to create default arguments
&lt;a class="heading-link" href="#use-function-definitions-to-create-default-arguments"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;We can utilize methods on function types when the arguments of a function is almost always the same:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyComplicatedFunc&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;someReallyComplicatedStruct&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;d&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onlyThingThatMatters&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;f&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyComplicatedFunc&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;invoke&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onlyThingThatMatters&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;f&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;some default string&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4321&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;someReallyComplicatedStruct&lt;/span&gt;{ &lt;span style="color:#75715e"&gt;/* values that don&amp;#39;t change. */&lt;/span&gt;}, &lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should make invoking this function with the &amp;lsquo;default&amp;rsquo; arguments internally in the package very simple.&lt;/p&gt;
&lt;p&gt;Note: This is a neat trick, but just because you can doesn&amp;rsquo;t mean you should.
I don&amp;rsquo;t really endorse this pattern, and haven&amp;rsquo;t really seen it used in production code anywhere.&lt;/p&gt;
&lt;h3 id="use-type-aliases-for-documentation"&gt;
Use type aliases for documentation
&lt;a class="heading-link" href="#use-type-aliases-for-documentation"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Occasionally, a function parameter could use some additional documentation (including when the parameter itself is a function).
You &lt;strong&gt;could&lt;/strong&gt; define a function type in order to attach some additional godocs, however I recommend using type aliases in this case.
The only difference is adding a &lt;code&gt;=&lt;/code&gt; between the type name and its definition.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyComplicatedFunc&lt;/span&gt; = &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;someReallyComplicatedStruct&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;d&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onlyThingThatMatters&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The difference between type aliases and type definitions is outside the scope of this article, but one key result is that you cannot attach methods to this type.
Type aliases emphasise the intent to only add documentation.
Additionally, since this contrived example shows a very long function signature, you can see how type aliases (and type definitions) can make code shorter and more readable.&lt;/p&gt;</description></item><item><title>mokku -- How I built a Go Mocking framework in 5 days</title><link>https://kinbiko.com/posts/2020-03-28-mokku/</link><pubDate>Wed, 18 Mar 2020 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2020-03-28-mokku/</guid><description>&lt;p&gt;This past week I&amp;rsquo;ve had the privilege of having a Hack Week where I work, where we can work on whatever we wanted.
I ended up building &lt;a href="https://github.com/kinbiko/mokku" class="external-link" target="_blank" rel="noopener"&gt;Mokku&lt;/a&gt; &amp;ndash; a mocking framework for Go that gets out of your way.&lt;/p&gt;
&lt;h2 id="key-features"&gt;
Key features
&lt;a class="heading-link" href="#key-features"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Invisible: No hard (&lt;code&gt;import&lt;/code&gt;) or soft (&lt;code&gt;//go:generate&lt;/code&gt;) dependencies to add to your codebase.&lt;/li&gt;
&lt;li&gt;Unintrusive: Can be included in any developer&amp;rsquo;s workflow. Doesn&amp;rsquo;t dictate or enforce how you use it after it&amp;rsquo;s written.&lt;/li&gt;
&lt;li&gt;Unassuming: Doesn&amp;rsquo;t care about package paths or even if your file compiles. All it wants is an interface.&lt;/li&gt;
&lt;li&gt;Vanilla: It&amp;rsquo;s basically a shortcut to generating the mocks you&amp;rsquo;d probably write yourself if you wrote the mocks manually.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ve been wanting to write this mocking framework for a while now.
So when I finally had the opportunity to work on this full time for a week, I implemented all the techniques and processes I personally prefer (I was developing this project on my own) and genuinely had a good time working on this.
You can check out the project in its entirety on &lt;a href="https://github.com/kinbiko/mokku" class="external-link" target="_blank" rel="noopener"&gt;GitHub&lt;/a&gt;, so I won&amp;rsquo;t go into the details of how to use it etc. here.&lt;/p&gt;
&lt;p&gt;Instead, I&amp;rsquo;d like to share how the development process went.
As opposed to most technical blog posts, and indeed most of my own blog posts, this won&amp;rsquo;t be an article where I try and tell you how you should do things.
I&amp;rsquo;m just going to share what I did, and some of my thoughts around how things went.&lt;/p&gt;
&lt;p&gt;You know, like a blog.&lt;/p&gt;
&lt;p&gt;But first, a bit of background.&lt;/p&gt;
&lt;h2 id="gomock-go-away"&gt;
GoMock?! Go away
&lt;a class="heading-link" href="#gomock-go-away"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I had two main sources of &amp;lsquo;fuel&amp;rsquo; so to speak, for delivering Mokku.
The first was the frustration I&amp;rsquo;ve had when working with GoMock.
Its super terse error messages, annoying gotchas and things to remember left me with a strong desire to make something &lt;strong&gt;SIMPLE&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The second source of fuel is more of an inspiration.
&lt;a href="https://github.com/matryer/moq" class="external-link" target="_blank" rel="noopener"&gt;Mat Ryer&amp;rsquo;s Moq mocking framework&lt;/a&gt; ticks most of what I was looking for in a mocking framework, and then some.
In fact, the usage of Mokku is very similar to how you use Moq.
I chose to drop some of the bells and whistles that come with Moq (maybe I&amp;rsquo;ll incorporate them as command line flags down the line), and went with what in my opinion is an even simpler approach.
For example, instead of storing all arguments that have been passed to the mocks by default (and having them be safe for concurrent access), I opted to &lt;code&gt;defer&lt;/code&gt; the implementation of this logic to the users (see what I did there? &amp;hellip; I&amp;rsquo;ll see myself out).&lt;/p&gt;
&lt;h2 id="day-1-planning"&gt;
Day 1: Planning
&lt;a class="heading-link" href="#day-1-planning"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I spent the first day quickly putting together a rough project plan and product and engineering designs in the Wiki of the GitHub project (you can still find it there).
I knew from the start that the purpose of doing these planning activities wasn&amp;rsquo;t to know exactly how I was going to do things.
It was more to see the scope of the project that I could fit into this one week I had available to me.
&lt;a href="https://basecamp.com/shapeup/1.2-chapter-03" class="external-link" target="_blank" rel="noopener"&gt;Appetite, not estimate&lt;/a&gt;.
Luckily, my gut feel told me I could get quite a fair bit done in the allotted time, without skimping out on quality.&lt;/p&gt;
&lt;p&gt;As part of doing the quick engineering design, I dove deeper into how Moq worked under the hood, and was able to steal some of the ideas used.
The main idea I stole was to use the &lt;code&gt;text/template&lt;/code&gt; to generate the mocked structs.
In hindsight this is an obvious choice, I think I had just forgotten about this package&amp;rsquo;s existence.
It &lt;em&gt;is&lt;/em&gt; somewhat overshadowed by its HTML counterpart.&lt;/p&gt;
&lt;p&gt;In terms of actual product value, by the end of the first day I barely managed to scrape together a skeleton with a dummy test running in CI.
But that&amp;rsquo;s fine.
The tree still stands, but the axe is sharp.&lt;/p&gt;
&lt;h2 id="day-2-parsing"&gt;
Day 2: Parsing
&lt;a class="heading-link" href="#day-2-parsing"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I spent the second day doing the initial version of a &amp;lsquo;parser&amp;rsquo;, that would read a given &lt;code&gt;interface&lt;/code&gt; definition given as &lt;code&gt;[]byte&lt;/code&gt;, and identify its comprising components.
I used test driven development in this endeavour as I had pretty good idea of what I wanted to get out of it (I knew the input I&amp;rsquo;d get, I knew the output I wanted), but didn&amp;rsquo;t actually know how to implement it yet.
I initially thought I could use the &lt;code&gt;go/parser&lt;/code&gt; package from the standard library, but this wasn&amp;rsquo;t quite as flexible as I needed it to be.
After looking around for a bit longer I found this package&amp;rsquo;s neighbour, &lt;code&gt;go/scanner&lt;/code&gt;, which was exactly what I wanted.
The scanner was able to read a byte slice one &amp;rsquo;token&amp;rsquo; at a time, and tell me what special meaning it had in the Go language, if any.
However, it didn&amp;rsquo;t require the code to actually compile, which was exactly the simplicity I was looking for.&lt;/p&gt;
&lt;p&gt;I had a bit of extra time during the day that I spent on reading up on Go templates.
I&amp;rsquo;ve known about them for a while, but I&amp;rsquo;ve never actually used them before.
I have 0 doubt this is still obvious from reading the template code&amp;hellip;&lt;/p&gt;
&lt;h2 id="day-3-templates"&gt;
Day 3: Templates
&lt;a class="heading-link" href="#day-3-templates"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;OK the title lies, I spent about half of the time getting the templates to work, and fixing bugs in the parser when I realised that I needed more information than what I previously thought.
The rest was spent hooking together the parser, and creating a runnable binary.
This day was also the day where I had to decide if I wanted to present what I had made internally to the company. I went for &amp;lsquo;yes&amp;rsquo;, not at all knowing what that actually would entail.&lt;/p&gt;
&lt;h2 id="day-4-make-things-presentable"&gt;
Day 4: Make Things Presentable
&lt;a class="heading-link" href="#day-4-make-things-presentable"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;At the start of the day I already had a working prototype. There were a couple of bugs still around (e.g. &lt;code&gt;...&lt;/code&gt; for varargs didn&amp;rsquo;t quite work), but those were squashed relatively quickly.
Now I just had to make it so that people could quickly learn how to use it, &lt;strong&gt;and want to&lt;/strong&gt; use it.
This meant creating an amazing README. &lt;a href="https://github.com/kinbiko/mokku/blob/master/README.md" class="external-link" target="_blank" rel="noopener"&gt;I&amp;rsquo;m quite happy with how it all turned out&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I paid a designer on Fiverr to create a simple logo for the project, and I got what I paid for. You&amp;rsquo;re free to interpret that how you will, but I&amp;rsquo;m not complaining.&lt;/p&gt;
&lt;p&gt;In order to really showcase the simplicity of the tool, I went an created an &lt;a href="https://asciinema.org/" class="external-link" target="_blank" rel="noopener"&gt;asciinema&lt;/a&gt; recording of how I would use it my day-to-day work.
Not gonna lie, I did &lt;strong&gt;a lot&lt;/strong&gt; of takes before I settled on a recording where I didn&amp;rsquo;t make that many typos (only 6).
I sped up the recording 2 times to not make it boring to watch.&lt;/p&gt;
&lt;p&gt;Side note, it turns out you cannot embed a video recording in a README, but you can embed a GIF.
Asciinema creates these really cool hybrid video/text files (you can copy/paste text from these hybrids), but I would rather have something that catches the eye in the README and quickly showcases Mokku.
So I had to install a couple of other tools to turn the recording I had stored locally into a GIF.&lt;/p&gt;
&lt;p&gt;The rest of the day was spent putting together slides for the presentation I was making to the company the next day.&lt;/p&gt;
&lt;h2 id="day-5-presentation"&gt;
Day 5: Presentation
&lt;a class="heading-link" href="#day-5-presentation"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I know very little about presenting work like this, but what little I do know I used.
Namely &lt;a href="https://kinbiko.com/software-engineering/why-how-what/" class="external-link" target="_blank" rel="noopener"&gt;start with why&lt;/a&gt; and putting only a couple of words on each slide, but having many slides.&lt;/p&gt;
&lt;p&gt;I made the repository public, did some final bit of clean up, and spent most of the rest of the day watching other presenters and preparing for my own presentation.
Since we were all working remotely (if you&amp;rsquo;re reading from the future: this happened back when the entire world was in quarantine) it&amp;rsquo;s really hard to tell how well the presentation went.
Honestly, I don&amp;rsquo;t even know if my slides were showing &amp;ndash; I just jumped into it hoping for the best.
No regrets!&lt;/p&gt;
&lt;h2 id="conclusion"&gt;
Conclusion
&lt;a class="heading-link" href="#conclusion"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m pretty happy with how it all went.
I ended up with a good implementation that not only works but it&amp;rsquo;s also something I&amp;rsquo;d be happy to iterate further on.
I do have some remaining work that needs to be done before I&amp;rsquo;m happy releasing a version 1 of Mokku.
If you&amp;rsquo;re new to Go or open source, there are &lt;a href="https://github.com/kinbiko/mokku/issues?q=is%3Aopen&amp;#43;is%3Aissue&amp;#43;label%3A%22good&amp;#43;first&amp;#43;issue%22" class="external-link" target="_blank" rel="noopener"&gt;several issues that you could help with if you wish&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Testing Tips for Beginner Gophers</title><link>https://kinbiko.com/posts/2020-02-22-testing-tips-for-beginner-gophers/</link><pubDate>Sat, 22 Feb 2020 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2020-02-22-testing-tips-for-beginner-gophers/</guid><description>&lt;p&gt;Let&amp;rsquo;s have a go at writing tests in Go.
Puns aside, testing in Go is baked into the language.
Assuming you&amp;rsquo;re comfortable with the &lt;a href="https://tour.golang.org/welcome/1" class="external-link" target="_blank" rel="noopener"&gt;Go basics&lt;/a&gt;, let&amp;rsquo;s get started with writing tests.
First of all, the way you run all tests in the current package is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ go test
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, unless you&amp;rsquo;ve got tests in your project nothing is going to execute.
Go tests have to follow these three rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The filename of all your test files &lt;strong&gt;must end with&lt;/strong&gt; &lt;code&gt;_test.go&lt;/code&gt; (including the underscore &lt;code&gt;_&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The test function names must start with the &lt;code&gt;Test&lt;/code&gt; prefix.&lt;/li&gt;
&lt;li&gt;The test functions must have exactly 1 parameter, of type &lt;code&gt;*testing.T&lt;/code&gt; (conventionally called &lt;code&gt;t&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thus a file called &lt;code&gt;something_test.go&lt;/code&gt; containing:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mypkg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;testing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestSomething&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;testing&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;is a minimal piece of code that counts as a test, and can be verified as such by running &lt;code&gt;go test&lt;/code&gt; in the same directory.&lt;/p&gt;
&lt;p&gt;As positively exhilarating as the above test was, it is useless, as it can never fail.
To make the test fail, we use the &lt;code&gt;*testing.T&lt;/code&gt; parameter.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestSomething&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;testing&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;t&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Errorf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;test failed&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we have a test that&amp;rsquo;s always failing.
This isn&amp;rsquo;t very useful, but it&amp;rsquo;s a start.
If we run this we get the following output:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;--- FAIL: TestSomething (0.00s)
something_test.go:6: test failed
FAIL
exit status 1
FAIL _/Users/kinbiko/repos/mypkg 0.005s
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="the-built-in-assertions-are-all-you-need"&gt;
The built-in assertions are all you need.
&lt;a class="heading-link" href="#the-built-in-assertions-are-all-you-need"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;There are two key methods on &lt;code&gt;t&lt;/code&gt; you need to know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;t.Errorf&lt;/code&gt; marks your test as failing, and prints the given message.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t.Fatalf&lt;/code&gt; does the same as &lt;code&gt;t.Errorf&lt;/code&gt;, but will stop the execution of the test at the line it&amp;rsquo;s called.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As the programmer, it&amp;rsquo;s your responsibility to identify whether or not a test should fail.
This means putting &lt;code&gt;if&lt;/code&gt;s in your test code, which might be surprising to you, especially if you&amp;rsquo;re coming from a language like Java, where the test framework includes various forms of equality checks for most assertions.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestFizzBuzz&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;testing&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fizzbuzz&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Fizz&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;t&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Errorf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;expected the 3rd FizzBuzz value to be &amp;#39;Fizz&amp;#39;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Personally, I prefer this more explicit way of writing test assertions, and you&amp;rsquo;ll see why in a sec, but if you&amp;rsquo;re set on avoing &lt;code&gt;if&lt;/code&gt;s, there&amp;rsquo;s a very popular &lt;a href="https://github.com/stretchr/testify" class="external-link" target="_blank" rel="noopener"&gt;testing library called Testify&lt;/a&gt; which exposes this XUnit-like testing syntax.&lt;/p&gt;
&lt;p&gt;Again, the built-in testing framework assumes you&amp;rsquo;ll write somewhat non-trivial code to make the right assertions.
This might sound like a bad thing, but it turns out breaking the convention of &amp;lsquo;dumb&amp;rsquo; tests allows for some pretty valuable techniques&amp;hellip;&lt;/p&gt;
&lt;h2 id="table-driven-tests"&gt;
Table-driven tests
&lt;a class="heading-link" href="#table-driven-tests"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Table-driven tests&lt;/em&gt; are a very common testing pattern in Go.
The general idea is that you define a &amp;ldquo;test table&amp;rdquo;: a slice of &amp;rsquo;test case&amp;rsquo; structs, that you iterate over, executing the same bit of test code over and over again for all the test cases.
It&amp;rsquo;s perhaps easier to show how this works with an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestFizzBuzz&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;testing&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Define the test table: an anonymous struct type that&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// we define and initialise a slice of immediately.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;tt&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; []&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;in&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Fizz&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;4&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Buzz&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Fizz&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;7&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Buzz&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;FizzBuzz&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;FizzBuzz&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Iterate over all test cases&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;tc&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;range&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tt&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;got&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fizzbuzz&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;tc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;); &lt;span style="color:#a6e22e"&gt;got&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// A good human readable assertion message makes understanding test failures easy!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;t&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Errorf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;expected the FizzBuzz value number %d to be &amp;#39;%s&amp;#39; but was &amp;#39;%s&amp;#39;&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;tc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;tc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;got&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice how &lt;code&gt;t.Errorf&lt;/code&gt; forces us to think about and write our own assertion message.
This is a good thing.
You get to choose a human-readable message including exactly the information you care about, instead of relying on a testing framework&amp;rsquo;s default message.&lt;/p&gt;
&lt;p&gt;The authors of Testify have of course thought about this, and allows for custom assertion messages, but it doesn&amp;rsquo;t force you to write these.
In my experience, often when using Testify these assertion messages are not written, and even when they are included it feels like a chore, which in turn leads to less thought being put into these assertion messages, losing their merit.
This is a large part of why I prefer the standard library&amp;rsquo;s &lt;code&gt;&amp;quot;testing&amp;quot;&lt;/code&gt; framework out of the box.
This is of course personal (or team) preference, and I&amp;rsquo;ll let you make up your own mind.&lt;/p&gt;
&lt;h2 id="sub-tests"&gt;
Sub-tests
&lt;a class="heading-link" href="#sub-tests"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;For simple programs like FizzBuzz, the test cases are very simple: One input, one output.
More commonly in &amp;lsquo;real&amp;rsquo; apps, you&amp;rsquo;re testing more complex business logic.
In these cases you probably want more &amp;ldquo;context&amp;rdquo; around what exactly you&amp;rsquo;re testing.
This is where sub-tests come in.&lt;/p&gt;
&lt;p&gt;Sub-tests are effectively inner tests within outer tests, which allow you to give your inner tests a name, and share some common setup.
Let&amp;rsquo;s examine how sub-tests are useful by writing some tests for a fictional app that allows users to &amp;rsquo;like&amp;rsquo; posts, similar to Facebook or Instagram.
Here&amp;rsquo;s a test for a certain feature of this app, try and see if you can understand what the &lt;code&gt;likesExcerpt&lt;/code&gt; function does by reading the tests.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestLikesExcerpt&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;testing&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;jeffords&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Jeffords&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;diaz&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Diaz&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;scully&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Scully&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;peralta&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Peralta&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;boyle&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Boyle&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;holt&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Holt&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;santiago&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Santiago&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;hitchcock&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Hitchcock&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;linetti&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Linetti&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;db&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setUpDB&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;db&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Insert&lt;/span&gt;([]&lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;jeffords&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;diaz&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;scully&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;peralta&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;boyle&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;santiago&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;hitchcock&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;holt&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;linetti&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;s&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;service&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;db&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;db&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Note: it&amp;#39;s not uncommon to define the for loop and the test table at the same time.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;tc&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;range&lt;/span&gt; []&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;in&lt;/span&gt; []&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;given no likes then invite user to like&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: []&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;{},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Be the first to like this&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;given one like then name the user&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: []&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;scully&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Scully likes this&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;given two likes then name both users&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: []&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;jeffords&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;diaz&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Jeffords and Diaz like this&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;given three likes then name the first two users and count the last user (singular)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: []&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;jeffords&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;diaz&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;scully&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Jeffords, Diaz, and 1 more person likes this&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;given more than three users then name the first two users and count the rest (plural)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;: []&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;jeffords&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;diaz&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;scully&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;boyle&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;peralta&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;linetti&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Jeffords, Diaz, and 4 others like this&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Note: We&amp;#39;re intentionally shadowing the t parameter in the subtest,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// by defining a parameter with the same name.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;t&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Run&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;tc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;testing&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;got&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;likesExcerpt&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;tc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;in&lt;/span&gt;&lt;span style="color:#f92672"&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Note: even though we&amp;#39;re using Fatalf here, we only interrupt the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// innermost subtest; the other test cases will still run.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;t&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Fatalf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;didn&amp;#39;t expect an error but got &amp;#39;%s&amp;#39;&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Error&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;got&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;tc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;t&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Errorf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;expected excerpt &amp;#39;%s&amp;#39; but got &amp;#39;%s&amp;#39;&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;tc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;exp&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;got&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;t&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Run&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;errors out on unrecognised IDs&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;t&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;testing&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;likesExcerpt&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;scully&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;123&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;boyle&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;456&lt;/span&gt;); &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;t&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Errorf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;expected an error relating to unrecognised IDs but didn&amp;#39;t get one&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above creates a subtest per test case, using the test case name as the name of the subtest.
This makes it easier to understand which test case failed when you have multiple subtests.
This is because in the case of a test failure, it will print the name of the test that failed prior to the assertion message.
For example, if the &lt;code&gt;&amp;quot;given three likes then name the first two users and count the last user (singular)&amp;quot;&lt;/code&gt; test case failed, we would get the following message:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;--- FAIL: TestLikesExcerpt (0.00s)
--- FAIL: TestLikesExcerpt/given_three_likes_then_name_the_first_two_users_and_count_the_last_user_(singular) (0.00s)
likes_test.go:87: expected excerpt &amp;#39;Jeffords, Diaz, and 1 more person likes this&amp;#39; but got &amp;#39;Jeffords, Diaz, and 1 others like this&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;which explicitly names the subtest that failed, enabling us to quickly identify what might be wrong.&lt;/p&gt;
&lt;p&gt;Also notice the second single subtest that checks an error case.
Because we did all the hard work of defining the users and setting up the &lt;code&gt;service&lt;/code&gt; and &lt;code&gt;db&lt;/code&gt; in the outer test, we can use them in both sub tests.&lt;/p&gt;
&lt;h2 id="integration-tests-vs-unit-tests-the-_test-package"&gt;
Integration tests vs unit tests; the &lt;code&gt;_test&lt;/code&gt; package.
&lt;a class="heading-link" href="#integration-tests-vs-unit-tests-the-_test-package"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;For any package, e.g. &lt;code&gt;storage&lt;/code&gt;, you can optionally use a &lt;code&gt;storage_test&lt;/code&gt; package in the same directory to use as a package for just test logic.
The idea behind the &lt;code&gt;storage_test&lt;/code&gt; package is to test only the types, funcs, methods, and variables that are public in the &lt;code&gt;storage&lt;/code&gt; package.
If you&amp;rsquo;ve written code in other languages such as Java or Ruby, you might be used to seeing these types of tests in different directories altogether.
I like Go&amp;rsquo;s choice of allowing a &lt;code&gt;_test&lt;/code&gt; package in the same directory, as it makes it easier to find the production code for a given test, and vice versa.&lt;/p&gt;
&lt;p&gt;Writing tests like this is &lt;em&gt;optional&lt;/em&gt;, in that you&amp;rsquo;re not required to use this package for your tests.
There&amp;rsquo;s nothing preventing you from writing exactly the same tests within the &lt;code&gt;storage&lt;/code&gt; package directly, but there are some advantages to using the &lt;code&gt;_test&lt;/code&gt; package:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You&amp;rsquo;re testing the code from the same point of view that your users are using it, giving you a better feel for how your package is to use.&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;re not relying on implementation details of your package, and your tests are less rigid and fragile.&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;re likely to find a necessary and sufficient level of dependency injection required for your package, helping you find the correct interfaces to demand in your package.&lt;/li&gt;
&lt;li&gt;Compilation errors in these tests probably indicate a breaking change in your API, informing you that you might need to do a major version bump.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we call the &lt;code&gt;storage_test&lt;/code&gt; package tests &amp;lsquo;Integration tests&amp;rsquo; and the &lt;code&gt;storage&lt;/code&gt; tests &amp;lsquo;unit tests&amp;rsquo;, then it might be tempting to believe that all tests should be integration tests.
I reject this idea, and believe you get the most value out of your code and time by picking your battles around when to write unit tests and when to write integration tests.
In general, I default to writing integration tests, and introduce unit tests for complex and &amp;ldquo;hard to hit&amp;rdquo; logic.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at an example of what the files of a &lt;code&gt;storage&lt;/code&gt; package might look like:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cache.go
cache_test.go &amp;lt;-- `package storage`: unit test of the cache implementation details because caching logic is hard.
storage.go
storage_test.go &amp;lt;-- `package storage_test`: integration test of storage, which uses the logic of cache.go internally.
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>jsonassert -- A test utility for comparing and verifying JSON</title><link>https://kinbiko.com/posts/2019-02-06-jsonassert/</link><pubDate>Wed, 06 Feb 2019 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2019-02-06-jsonassert/</guid><description>&lt;p&gt;Today I released v1.0.0 of a &lt;a href="https://github.com/kinbiko/jsonassert" class="external-link" target="_blank" rel="noopener"&gt;Go package called jsonassert&lt;/a&gt;.
It is my first self-motivated open source contribution that I think has a chance of being useful to someone other than just myself.
Okay, &lt;a href="https://github.com/kinbiko/bugsnag-maven-plugin" class="external-link" target="_blank" rel="noopener"&gt;that&amp;rsquo;s not quite true&lt;/a&gt; but it&amp;rsquo;s the first one I&amp;rsquo;ve written in Go.&lt;/p&gt;
&lt;p&gt;I realised the need for this package when attempting to increase the test confidence of a relatively untested package that sends JSON to a server.
There was no easy way of making assertions against this JSON body, at least not without moving to an entirely new test framework.
I&amp;rsquo;m a big fan of the &lt;code&gt;testing&lt;/code&gt; package in the Go standard library, and this was already being used elsewhere in the package I was working with.
So I settled for writing more lines of code than I would have liked, attempting to parse the JSON nested-object-by-nested-object as deserialising into a struct would defeat the purpose of the test.&lt;/p&gt;
&lt;p&gt;However, when doing slogging away at these SLOCs I kept being haunted by an urge to write this &lt;code&gt;jsonassert&lt;/code&gt; package.
At the beginning of this year, I announced that my new years resolution would be to do more uncomfortable things.
Well, one of those uncomfortable things was to &lt;a href="https://twitch.tv/kinbiko" class="external-link" target="_blank" rel="noopener"&gt;stream myself programming on Twitch&lt;/a&gt;, which I have done several times now (I bet you can&amp;rsquo;t figure out how to hit that &amp;lsquo;follow&amp;rsquo; button!).
The thing I&amp;rsquo;ve been streaming the most has been the development of this package, essentially from scratch.
Now that it&amp;rsquo;s released in what I believe to be in a production-ready state, I need to figure out what else I can hack on&amp;hellip;
Maybe a little tool that can help me study Japanese? We&amp;rsquo;ll see!&lt;/p&gt;
&lt;p&gt;Watch &lt;del&gt;this space&lt;/del&gt; my Twitch streams!&lt;/p&gt;</description></item><item><title>Feature-oriented package structures and the default access modifier</title><link>https://kinbiko.com/posts/2018-02-18-feature-oriented-package-structure-and-default-access-modifier/</link><pubDate>Sun, 18 Feb 2018 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2018-02-18-feature-oriented-package-structure-and-default-access-modifier/</guid><description>&lt;p&gt;In Java we have 4 access modifiers that can be applied to methods and
fields of a class. In descending order of visibility, they are:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; String publicModifier &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Anyone can access me&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;protected&lt;/span&gt; String protectedModifier &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Only accessible to classes in the same package as me, and my subclasses&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; String defaultModifier &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Only accessible to classes in the same package as me&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; String privateModifier &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Only accessible within this class&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This article is a love letter to the third in this list of modifiers, the
one-who-shall-not-be-named. It&amp;rsquo;s usually referred to the &amp;lsquo;default&amp;rsquo; or
&amp;lsquo;package-private&amp;rsquo; access modifier.&lt;/p&gt;
&lt;h2 id="be-aware-of-ingrained-rules-you-dont-fully-understand"&gt;
Be aware of ingrained rules you don&amp;rsquo;t fully understand
&lt;a class="heading-link" href="#be-aware-of-ingrained-rules-you-dont-fully-understand"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;When I first started learning Java, I read that you should never use the
default access modifier. This was because it wasn&amp;rsquo;t obvious if you had
thought about the desired visibility of your method or field, or if you were
being lazy or had just forgotten.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use &lt;code&gt;private&lt;/code&gt; wherever you can, &lt;code&gt;protected&lt;/code&gt; if you need access to it in your subclasses, and &lt;code&gt;public&lt;/code&gt; if you need it from the outside.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I didn&amp;rsquo;t question this decree at the time.&lt;/p&gt;
&lt;p&gt;Soon enough, I started feeling uncomfortable seeing methods and fields without
modifiers, and always applied the appropriate modifier whenever I found one,
according to the rule above.&lt;/p&gt;
&lt;p&gt;I later started using &lt;a href="https://www.jetbrains.com/idea/" class="external-link" target="_blank" rel="noopener"&gt;IntelliJ&lt;/a&gt; full time.
IntelliJ has a feature where it can infer the required access modifier by
looking at all the compiled code in its context, and see where the class member
is used. This feature is handy for seeing when something could be
private/protected, but I noticed that by default it also checks if its
visibility can be reduced to package-private. Surely that&amp;rsquo;s a feature everyone
disables. I know I did.&lt;/p&gt;
&lt;h2 id="prefer-feature-oriented-architectures-over-layer-oriented-architectures"&gt;
Prefer feature-oriented architectures over layer-oriented architectures.
&lt;a class="heading-link" href="#prefer-feature-oriented-architectures-over-layer-oriented-architectures"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I have grown to dislike this (very common) layer-oriented layout of packages:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;src/main/java/com/companyname/productname/
controller/
StuffController.java
ThingController.java
converter/
StuffConverter.java
ThingConverter.java
dao/
StuffDao.java
ThingDao.java
model/
Stuff.java
Thing.java
service/
StuffService.java
ThingService.java
util/
StuffHelper.java
ThingHelper.java
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This layer-oriented format is so common that it even appears in &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-structuring-your-code.html" class="external-link" target="_blank" rel="noopener"&gt;Spring&amp;rsquo;s
documentation&lt;/a&gt;,
and 95%+ of the projects I see use this format for web applications. This
diminishes the integrity of the architecture, implements the wrong kind of
seperation of concerns, and leads to code that&amp;rsquo;s harder to maintain and split
apart. A much cleaner approach is to organise your code by feature:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;src/main/java/com/companyname/productname/
stuff/
StuffController.java
StuffConverter.java
StuffDao.java
Stuff.java
StuffService.java
StuffHelper.java
thing/
ThingController.java
ThingConverter.java
ThingDao.java
Thing.java
ThingService.java
ThingHelper.java
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This approach gives you a clearer view of your architecture as it emphasises
&lt;em&gt;features over design patterns&lt;/em&gt;. More importantly, the coupling between
features is &lt;em&gt;necessarily&lt;/em&gt; more obvious. Any non-&lt;code&gt;Stuff&lt;/code&gt; related dependencies
inside any of the &lt;code&gt;Stuff&lt;/code&gt; classes are declared in the imports. I recommend
&lt;a href="http://www.javapractices.com/topic/TopicAction.do?Id=205" class="external-link" target="_blank" rel="noopener"&gt;this article&lt;/a&gt; if you
are interested in learning more about the perils of layer oriented
architectures.&lt;/p&gt;
&lt;h2 id="rethinking-best-practices"&gt;
Rethinking best practices
&lt;a class="heading-link" href="#rethinking-best-practices"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Allow me to diverge for a second and bring up a point I learned from the
JavaScript (no relation) community. Ever since I first started learning about
React, I&amp;rsquo;ve been plagued by this notion of &lt;a href="https://www.youtube.com/watch?v=x7cQ3mrcKaY" class="external-link" target="_blank" rel="noopener"&gt;rethinking best
practices&lt;/a&gt; and if it applies to
other best practices I&amp;rsquo;m currently following. If you squint you can see how
React is a prime example of a technology that embodies the feature-oriented
architecture in that it combines HTML and JavaScript (and often CSS as well) in
a single component. In other words, it associates your view logic (JS) with
your template (HTML/CSS) &amp;ndash; exactly because they are conceptually related
(highly cohesive). However, React components are not necessarily related to
each other (loosely coupled).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://kinbiko.com/img/react-arch.jpg" alt="diagram of conventional frontend architecture and the modern react architecture"&gt;&lt;/p&gt;
&lt;p&gt;Credit: &lt;a href="https://twitter.com/MicheleBertoli" class="external-link" target="_blank" rel="noopener"&gt;Michele Bertoli&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="rethinking-java-best-practices"&gt;
Rethinking Java best practices
&lt;a class="heading-link" href="#rethinking-java-best-practices"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Back to the default access modifier. I believe that the default access modifier
was designed with exactly the feature-oriented package structure in mind.
Say that you have a &lt;code&gt;StuffController&lt;/code&gt; and &lt;code&gt;StuffService&lt;/code&gt; that looks something
like the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; com.companyname.productname.controller;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; com.companyname.productname.converter.StuffConverter;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; com.companyname.productname.model.Stuff;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; com.companyname.productname.service.StuffService;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; java.util.Set;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@RestController&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StuffController&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffConverter converter;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffService service;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Autowired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StuffController&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffService service,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffConverter converter) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;converter&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; converter;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;service&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; service;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@GetMapping&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/names&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; List&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getAllNames&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; Set&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Stuff&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; stuff &lt;span style="color:#f92672"&gt;=&lt;/span&gt; service.&lt;span style="color:#a6e22e"&gt;findAllTheStuff&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; converter.&lt;span style="color:#a6e22e"&gt;extractAllNames&lt;/span&gt;(stuff);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; com.companyname.productname.service;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; com.companyname.productname.dao.StuffDao;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; com.companyname.productname.model.Stuff;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; java.util.Set;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.stereotype.Service;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StuffService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffDao dao;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Autowired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StuffService&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffDao dao) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dao&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dao;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; Set&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Stuff&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;findAllTheStuff&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Other logic...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; dao.&lt;span style="color:#a6e22e"&gt;getAllStuff&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we switch to the feature-oriented package structure and use the default
access modifier the way it was intended, we get terser code. Notice how all the
redundant imports went away.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; com.companyname.productname.stuff;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; java.util.Set;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@RestController&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StuffController&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffConverter converter;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffService service;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Autowired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; StuffController(&lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffService service,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffConverter converter) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;converter&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; converter;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;service&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; service;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@GetMapping&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/names&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; List&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getAllNames&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; Set&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Stuff&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; stuff &lt;span style="color:#f92672"&gt;=&lt;/span&gt; service.&lt;span style="color:#a6e22e"&gt;findAllTheStuff&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; converter.&lt;span style="color:#a6e22e"&gt;extractAllNames&lt;/span&gt;(stuff);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; com.companyname.productname.stuff;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; java.util.Set;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.stereotype.Service;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StuffService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffDao dao;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Autowired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; StuffService(&lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; StuffDao dao) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;dao&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dao;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Set&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Stuff&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;findAllTheStuff&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Other logic...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; dao.&lt;span style="color:#a6e22e"&gt;getAllStuff&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You may have noticed that I still keep &lt;code&gt;public&lt;/code&gt; in a couple of places where it&amp;rsquo;s not strictly necessary. I firmly believe that code should express its own intent. I tend to prefer code readability over code minimalism; two concepts that are related, but different. In the case of the controller &lt;code&gt;class&lt;/code&gt; I use &lt;code&gt;public&lt;/code&gt; to show that this class is in fact accessed from outside the package. Similarly, the &lt;code&gt;public&lt;/code&gt; &lt;code&gt;@GetMapping&lt;/code&gt; annotated method is accessed from outside the package as well.&lt;/p&gt;
&lt;p&gt;When adjusting to this new mindset of loving the default modifier, the lack of
a modifier on the &lt;code&gt;findAllTheStuff()&lt;/code&gt; method may feel uncomfortable at first.
I used the following mantra to guide my intuition until I got comfortable with
the access modifier nudity:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By default, we want this functionality to remain within the feature.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Anything else is one of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Explicitly made available to any class (&lt;code&gt;public&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Explicitly made available to subclasses (&lt;code&gt;protected&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Explicitly restricted to only this class (&lt;code&gt;private&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notice how the imports are now only classes that are unrelated to this feature.
Take advantage of this symbiosis between the default access modifier and
not having to explicitly import classes from the same package. How often do you
check the imports when you&amp;rsquo;re writing code or doing a code review? Chances are
they&amp;rsquo;re entirely ignored. I claim that imports are crucial in understanding the
coupling between units. Imports &lt;em&gt;within the feature&lt;/em&gt; do nothing but hide
excessive coupling in a forest of boilerplate code.&lt;/p&gt;
&lt;p&gt;Case in point: A developer &lt;a href="https://kinbiko.com/java/dependency-injection-patterns/" class="external-link" target="_blank" rel="noopener"&gt;skilled in the Spring
Framework&lt;/a&gt; might have
noticed the &lt;code&gt;@Autowired&lt;/code&gt; annotation from the imports alone, which is redundant
in both of these classes.&lt;/p&gt;
&lt;p&gt;In high-quality code I would expect that the quantity of methods increase as
the access modifier gets more restrictive. Perhaps the default modifier would
have been more intuitive had the absense of a modifier meant &lt;code&gt;private&lt;/code&gt; rather
than package-private. It certainly would have shaved many a character from my
classes. This is what I believe is the design flaw behind the default access
modifier, rather than its existence in the first place. Hindsight is 20/20 I
guess.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;
Conclusion
&lt;a class="heading-link" href="#conclusion"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;In today&amp;rsquo;s world of microservices and cloud architecture a common pattern for
managing large systems is extracting sprout microservices (read more about this
topic in &lt;a href="https://blog.bugsnag.com/modern-approach-to-legacy-code/" class="external-link" target="_blank" rel="noopener"&gt;my article in my company&amp;rsquo;s
blog&lt;/a&gt;). This is a
trivial exercise when the architecture of your service is oriented around
features rather than layers.&lt;/p&gt;
&lt;p&gt;The default access modifier in Java does have a purpose, and it&amp;rsquo;s one of
feature encapsulation. It&amp;rsquo;s such a shame that its use has become misunderstood
and frowned upon.&lt;/p&gt;
&lt;h4 id="ps"&gt;
PS:
&lt;a class="heading-link" href="#ps"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;I started writing this article before Java 9 came out but I have to say, I&amp;rsquo;m
really excited about Java 9. It comes with a module system that adds additional
encapsulation at a package level. For example, in Java 8 and earlier you could
override the implementation of package-private methods in any third party
library by placing your class in the library&amp;rsquo;s package and inheriting. This is
no longer possible. I expect that once this new module system has gained some
traction we&amp;rsquo;ll start seeing some new patterns around organising our code. I&amp;rsquo;m
hoping developers become more conscious of their package structure. Although,
I&amp;rsquo;m not holding my breath on that one.&lt;/p&gt;</description></item><item><title>Spring Dependency Injection Patterns -- The good, the bad, and the ugly</title><link>https://kinbiko.com/posts/2018-02-13-spring-dependency-injection-patterns/</link><pubDate>Tue, 13 Feb 2018 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2018-02-13-spring-dependency-injection-patterns/</guid><description>&lt;p&gt;Spring developers will be familiar with its powerful &lt;a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html" class="external-link" target="_blank" rel="noopener"&gt;Dependency Injection API&lt;/a&gt;.
It allows you to declare &lt;code&gt;@Bean&lt;/code&gt;s that Spring then instantiates and manages.
Any dependencies between these beans is then resolved by Spring and injected
automagically.&lt;/p&gt;
&lt;h2 id="three-annotation-based-injection-patterns"&gt;
Three Annotation-based Injection Patterns
&lt;a class="heading-link" href="#three-annotation-based-injection-patterns"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;There are three ways Spring lets you declare the dependencies of your class using annotations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Field injection (The bad)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyBean&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Autowired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; AnotherBean anotherBean;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Business logic...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setter injection (The ugly)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyBean&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; AnotherBean anotherBean;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Autowired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setAnotherBean&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; AnotherBean anotherBean) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;anotherBean&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; anotherBean;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Business logic...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Constructor Injection (The good)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyBean&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; AnotherBean anotherBean;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyBean&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; AnotherBean anotherBean) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;anotherBean&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; anotherBean;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Business logic...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="the-inconvenient-truth-about-field-injection"&gt;
The inconvenient truth about field injection
&lt;a class="heading-link" href="#the-inconvenient-truth-about-field-injection"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;The most common of all of these patterns is the field injection pattern. Most
likely because it&amp;rsquo;s the most convenient of the three patterns. Unfortunately,
because of it&amp;rsquo;s ubiquity, developers rarely learn about the other two patterns,
and the pros and cons associated with each of them.&lt;/p&gt;
&lt;h3 id="classes-using-field-injection-tend-to-become-harder-to-maintain"&gt;
Classes using field injection tend to become harder to maintain
&lt;a class="heading-link" href="#classes-using-field-injection-tend-to-become-harder-to-maintain"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;When you use the field injection pattern, and want to further add dependencies
to your class you only need to make a field, slap an &lt;code&gt;@Autowired&lt;/code&gt; or &lt;code&gt;@Inject&lt;/code&gt;
annotation on it and you&amp;rsquo;re good to go. At first this sounds great, but a few
months down the line you realise that your class has grown into a God class
that&amp;rsquo;s hard to manage. Granted, this may very well happen with the two other
patterns as well, but they force you to pay more attention to the dependencies
in your class.&lt;/p&gt;
&lt;h3 id="every-time-you-use-field-injection-a-unit-test-dies"&gt;
Every time you use field injection a unit test dies
&lt;a class="heading-link" href="#every-time-you-use-field-injection-a-unit-test-dies"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;This line has stuck with me since I saw &lt;a href="https://twitter.com/starbuxman" class="external-link" target="_blank" rel="noopener"&gt;Josh
Long&lt;/a&gt;&amp;rsquo;s &lt;a href="https://youtu.be/sbPSjI4tt10?t=29m22s" class="external-link" target="_blank" rel="noopener"&gt;talk on Spring
Boot&lt;/a&gt;, and in a sense is what motivated
me to write this article. How do you go about testing classes using field
injection? Chances are you&amp;rsquo;re somewhere along the path of memorising the
unintuitive &lt;code&gt;Mockito&lt;/code&gt; idiom for doing this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.junit.runner.RunWith;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.mockito.InjectMocks;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.mockito.Mock;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.mockito.runners.MockitoJUnitRunner;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@RunWith&lt;/span&gt;(MockitoJUnitRunner.&lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyBeanTest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Mock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; AnotherBean anotherBean;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@InjectMocks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; MyBean target;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Tests...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This reflection workaround is riddled with additional workarounds developers
have to master:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What if &lt;code&gt;MyBean&lt;/code&gt; has multiple dependencies of type &lt;code&gt;AnotherBean&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Should you create a new instance of the &lt;code&gt;target&lt;/code&gt;, or just declare it? Is there a difference?&lt;/li&gt;
&lt;li&gt;Do you have type safety with dependencies using generics?&lt;/li&gt;
&lt;li&gt;What if you want a real implementation of some of the dependencies, but not for others?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="classes-using-field-injection-are-non-final-but-are-prone-to-circular-dependencies"&gt;
Classes using field injection are non-final, but are prone to circular dependencies
&lt;a class="heading-link" href="#classes-using-field-injection-are-non-final-but-are-prone-to-circular-dependencies"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;If you try and declare an &lt;code&gt;@Autowired&lt;/code&gt; field as &lt;code&gt;final&lt;/code&gt;, you&amp;rsquo;ll get a compile
error. This is annoying in and of itself, as the field is only being set once
anyway! Unless you also annotate it as being &lt;code&gt;@Lazy&lt;/code&gt; Spring tries to resolve
your dependencies as part of a
&lt;a href="https://en.wikipedia.org/wiki/Directed_acyclic_graph" class="external-link" target="_blank" rel="noopener"&gt;DAG&lt;/a&gt; during startup, and
your field may be the source of a &lt;code&gt;BeanCurrentlyInCreationException&lt;/code&gt; due to
unexpected circular dependencies.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;A&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Autowired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; B b;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;B&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Autowired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; C c;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;C&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Autowired&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; A a;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The problem is &lt;strong&gt;never&lt;/strong&gt; this simple, and the actual problem tends to span
dozens of classes through a maze of inheritance, libraries and across architecture
boundaries. This problem can be resolved by either making one of the
dependencies not required (allow field to be null with &lt;code&gt;@Autowired(required = false)&lt;/code&gt;) or lazy (set field after resolving beans that depend on this bean with
&lt;code&gt;@Lazy&lt;/code&gt;). As everyone who have experienced this dreadful exception knows,
finding exactly which beans make up this circle is usually a long and arduous
endeavour. And once you have found all the pieces to your puzzle, which
dependency do you sacrifice? How do you document this decision properly?&lt;/p&gt;
&lt;p&gt;There are &lt;a href="http://www.baeldung.com/circular-dependencies-in-spring" class="external-link" target="_blank" rel="noopener"&gt;unreasonably many
workarounds&lt;/a&gt; to
solving the circular dependency problem, but hopefully by now something is
starting to smell.&lt;/p&gt;
&lt;h4 id="pros"&gt;
Pros
&lt;a class="heading-link" href="#pros"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The most terse of all the patterns.&lt;/li&gt;
&lt;li&gt;Most Java developers are aware of this pattern.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="cons"&gt;
Cons
&lt;a class="heading-link" href="#cons"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Convenience tends to hide code design red flags.&lt;/li&gt;
&lt;li&gt;Hard to test.&lt;/li&gt;
&lt;li&gt;Dependencies are unnecessarily mutable.&lt;/li&gt;
&lt;li&gt;Prone to circular dependency issues.&lt;/li&gt;
&lt;li&gt;Requires the use of (multiple) Spring or Java EE annotations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="public-void-setdependencydependency-dependency"&gt;
public void setDependency(Dependency dependency)
&lt;a class="heading-link" href="#public-void-setdependencydependency-dependency"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;h3 id="boilerplate-and-encapsulation"&gt;
Boilerplate and encapsulation
&lt;a class="heading-link" href="#boilerplate-and-encapsulation"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Among all the patterns, the setter injection pattern has the most boilerplate
by far. Each bean must have a setter and each setter must be decorated with an
&lt;code&gt;@Autowired&lt;/code&gt; or &lt;code&gt;@Inject&lt;/code&gt; annotation. Although this boilerplate definitely
solves the problem of not thinking about the amount of dependencies you&amp;rsquo;re
injecting into your class (the plethora of setters in your class should be a
dead giveaway), it comes with another design smell. You&amp;rsquo;re violating
encapsulation by exposing the innards of your class.&lt;/p&gt;
&lt;h3 id="classes-using-setter-injection-make-testing-easy"&gt;
Classes using setter injection make testing easy
&lt;a class="heading-link" href="#classes-using-setter-injection-make-testing-easy"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s no reflection magic required. Just set the dependencies you wish you had.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.junit.Before;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.mockito.Mockito;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyBeanTest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; MyBean target &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; MyBean();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; AnotherBean anotherBean &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Mockito.&lt;span style="color:#a6e22e"&gt;mock&lt;/span&gt;(AnotherBean.&lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Before&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setUp&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myBean.&lt;span style="color:#a6e22e"&gt;setAnotherBean&lt;/span&gt;(anotherBean);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Tests...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="classes-using-setter-injection-are-immune-to-circular-dependencies"&gt;
Classes using setter injection are immune to circular dependencies
&lt;a class="heading-link" href="#classes-using-setter-injection-are-immune-to-circular-dependencies"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;In using this pattern, Spring doesn&amp;rsquo;t try to represent your beans in a DAG,
which means that &lt;em&gt;circular dependencies are permitted&lt;/em&gt;, but it also means that
&lt;em&gt;circular dependencies are permitted&lt;/em&gt;. Allowing circular dependencies is a
double-edged sword. You won&amp;rsquo;t have to debug the nasty issues that occur as a
result of circular dependencies, but your code is much harder to break apart
later on. The &lt;code&gt;BeanCurrentlyInCreationException&lt;/code&gt; is in fact informing you, on
startup, that your design is flawed.&lt;/p&gt;
&lt;h4 id="pros-1"&gt;
Pros
&lt;a class="heading-link" href="#pros-1"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Immune to circular dependency issues.&lt;/li&gt;
&lt;li&gt;Highly coupled classes are easily identified as setters are added.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="cons-1"&gt;
Cons
&lt;a class="heading-link" href="#cons-1"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Violates encapsulation.&lt;/li&gt;
&lt;li&gt;Circular dependencies are hidden.&lt;/li&gt;
&lt;li&gt;The most boilerplate code of the three patterns.&lt;/li&gt;
&lt;li&gt;Dependencies are unnecessarily mutable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-solution-constructor-injection"&gt;
The solution: Constructor injection
&lt;a class="heading-link" href="#the-solution-constructor-injection"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;It turns out that the best solution to dependency injection is constructor
injection. Newer platforms that support DI, such as Angular, have
learned the lessons from other platforms and only support constructor
injection.&lt;/p&gt;
&lt;h3 id="constructor-injection-exposes-excessive-coupling"&gt;
Constructor injection exposes excessive coupling
&lt;a class="heading-link" href="#constructor-injection-exposes-excessive-coupling"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Whenever your class needs a new dependency you&amp;rsquo;re forced to add it to the
constructor&amp;rsquo;s parameters. This in turn forces you to recognise the amount of
coupling in your class. I&amp;rsquo;ve found that fewer than 3 dependencies is good, and
anything above 5 is begging for refactoring. Counting my dependencies is a
piece of cake when they&amp;rsquo;re defined on just a few contiguous lines.&lt;/p&gt;
&lt;p&gt;As an added bonus, since &lt;code&gt;final&lt;/code&gt; fields can be initialised in the constructor,
our dependencies can be immutable - as they should be!&lt;/p&gt;
&lt;h3 id="testing-constructor-injected-classes-is-trivial"&gt;
Testing constructor injected classes is trivial
&lt;a class="heading-link" href="#testing-constructor-injected-classes-is-trivial"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s arguably even easier than with setter injection.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.mockito.Mockito;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyBeanTest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; AnotherBean anotherBean &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Mockito.&lt;span style="color:#a6e22e"&gt;mock&lt;/span&gt;(AnotherBean.&lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; MyBean target &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; MyBean(anotherBean);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//Tests...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="constructor-injected-subclasses-must-have-non-default-constructors"&gt;
Constructor injected subclasses must have non-default constructors
&lt;a class="heading-link" href="#constructor-injected-subclasses-must-have-non-default-constructors"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Any subclass of a class using constructor injection must have a constructor
that calls the parent constructor. This is annoying if you have inherited
Spring components. I personally haven&amp;rsquo;t run into this very often. I try and
avoid injected dependencies in parent components - usually done through
&lt;a href="https://en.wikipedia.org/wiki/Composition_over_inheritance" class="external-link" target="_blank" rel="noopener"&gt;composition over
inheritance&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="pros-2"&gt;
Pros
&lt;a class="heading-link" href="#pros-2"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Dependencies can be immutable.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spring.io/blog/2007/07/11/setter-injection-versus-constructor-injection-and-the-use-of-required" class="external-link" target="_blank" rel="noopener"&gt;Recommended by
Spring&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Easiest to test out of all the patterns.&lt;/li&gt;
&lt;li&gt;Highly coupled classes are easily identified as constructor parameters grow.&lt;/li&gt;
&lt;li&gt;Familiar to developers coming from other platforms.&lt;/li&gt;
&lt;li&gt;No dependency on the &lt;code&gt;@Autowired&lt;/code&gt; annotation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="cons-2"&gt;
Cons
&lt;a class="heading-link" href="#cons-2"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Constructors trickle down to subclasses.&lt;/li&gt;
&lt;li&gt;Prone to circular dependency issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;
Conclusion
&lt;a class="heading-link" href="#conclusion"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Use the constructor injection pattern.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are times where the other patterns make sense too, but &amp;ldquo;for the sake of
being consistent with the rest of the codebase&amp;rdquo;, and &amp;ldquo;it&amp;rsquo;s just easier to use
the field injection pattern&amp;rdquo; are not valid excuses.&lt;/p&gt;
&lt;p&gt;For example, using the setter injection pattern is a good &lt;em&gt;intermediary&lt;/em&gt; step
when migrating from beans declared in XML files that already use the setter
pattern, or when you need to fix a &lt;code&gt;BeanCurrentlyInCreationException&lt;/code&gt; in
production, ASAP (not that you should ever end up in that position anyway).&lt;/p&gt;
&lt;p&gt;Even the field injection pattern is sufficient when, say, sketching out a
solution or answering questions on StackOverflow, unless their question is
about dependency injection in Java of course. In which case you should refer
them to this article.&lt;/p&gt;</description></item><item><title>Git and GitHub Workshop</title><link>https://kinbiko.com/talks/2018-01-31-git-workshop/</link><pubDate>Wed, 31 Jan 2018 00:00:00 +0000</pubDate><guid>https://kinbiko.com/talks/2018-01-31-git-workshop/</guid><description>&lt;p&gt;This event is for beginners, and covers fundamental Git concepts from scratch.&lt;/p&gt;</description></item><item><title> 10 Basic Shell Commands Every Beginner Should Know</title><link>https://kinbiko.com/posts/2018-01-14-10-basic-shell-commands-every-beginner-should-know/</link><pubDate>Sun, 14 Jan 2018 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2018-01-14-10-basic-shell-commands-every-beginner-should-know/</guid><description>&lt;p&gt;If you aspire to be a developer, sys-admin, or some other profession that relies on computers outside of word documents and excel spreadsheets then you ought to be comfortable with a command line.&lt;/p&gt;
&lt;p&gt;Software and IT professionals love their command-lines as it is &lt;a href="http://www.commitstrip.com/en/2016/12/22/terminal-forever/" class="external-link" target="_blank" rel="noopener"&gt;much more powerful&lt;/a&gt; than any &lt;a href="https://en.wikipedia.org/wiki/Graphical_user_interface" class="external-link" target="_blank" rel="noopener"&gt;GUI&lt;/a&gt; could ever be. This article aims to get you started from no prior knowledge.&lt;/p&gt;
&lt;p&gt;If this is completely new material for you, I recommend that you keep a Finder/Windows Explorer/etc. window open to understand what&amp;rsquo;s going on in familiar environments.&lt;/p&gt;
&lt;h2 id="the-difference-between-shells-and-terminals"&gt;
The difference between shells and terminals
&lt;a class="heading-link" href="#the-difference-between-shells-and-terminals"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;A terminal is a program with a menu bar and icon in your application bar etc. that provides a window into a shell. For the purpose of this article, a &amp;lsquo;shell&amp;rsquo; is a low-level program that executes commands. The shell we&amp;rsquo;ll be discussing in this article is the de facto industry standard; &amp;lsquo;Bash&amp;rsquo; (Bourne-Again SHell), although shells like Zsh (my personal favourite) and Fish are often used among professionals.&lt;/p&gt;
&lt;h4 id="examples-of-terminals-to-run-bash-in"&gt;
Examples of Terminals to run Bash in:
&lt;a class="heading-link" href="#examples-of-terminals-to-run-bash-in"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Windows: All Windows computers ship with a proprietary terminal called &amp;lsquo;cmd&amp;rsquo;, and recent releases of Windows also ship with the &amp;lsquo;Windows Powershell&amp;rsquo;. Neither of these can run Bash easily, and the content of this article does not apply to these. Author&amp;rsquo;s opinion: Both of these terminals/shells are crude and immature, although cmd much more so than Powershell. You can install other terminals on Windows as well, with the most popular one being Cygwin. To get Cygwin up and running quickly (its own installer is definitely non-trivial for beginners) I suggest you install &lt;a href="https://git-scm.com" class="external-link" target="_blank" rel="noopener"&gt;Git&lt;/a&gt; and thereby also Git-Bash.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mac: All Macs ship with a pretty good terminal application called &amp;lsquo;Terminal&amp;rsquo;. There is also a free and more powerful terminal called &amp;lsquo;iTerm2&amp;rsquo;. Using just Terminal is fine for the purposes of this article.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Linux: &amp;lsquo;gnome-terminal&amp;rsquo;, &amp;lsquo;guake&amp;rsquo;, &amp;lsquo;xterm&amp;rsquo;, &amp;lsquo;konsole&amp;rsquo;, &amp;rsquo;terminator&amp;rsquo;, &amp;rsquo;termite&amp;rsquo;&amp;hellip; If you&amp;rsquo;re running Linux you probably have a favourite already. Basically any Linux terminal will work for the purposes of this article.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cd-navigate-around-in-the-file-system"&gt;
cd: Navigate around in the file system
&lt;a class="heading-link" href="#cd-navigate-around-in-the-file-system"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;To navigate between directories you use &lt;code&gt;cd &amp;lt;path to directory&amp;gt;&lt;/code&gt; (&amp;ldquo;Change directory&amp;rdquo;)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd Documents
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;will take you to the Documents directory inside your current directory. To navigate to nested directories in a single command separate the directory names with a forward-slash.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd Documents/Important/Invoices
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="special-paths"&gt;
Special paths:
&lt;a class="heading-link" href="#special-paths"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;/&lt;/code&gt; (forward-slash): On Macs and Linux computers (Unix-like operating systems) the &lt;code&gt;/&lt;/code&gt; path is called &amp;lsquo;root&amp;rsquo;, and is the highest directory you can go to. All directories and files exist somewhere below &lt;code&gt;/&lt;/code&gt;. Windows is a bit different because it exposes disk drives as separate entities, and therefore &lt;code&gt;/&lt;/code&gt; may not make much intuitive sense.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;~&lt;/code&gt; (tilde): The Home directory of the current user. Most of the files and directories you&amp;rsquo;re familiar will exist here. E.g. Music, Documents, Downloads etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;.&lt;/code&gt; (single full stop): The &lt;em&gt;current&lt;/em&gt; directory. It may not be obvious just yet why this is useful, but it will with time (you are encouraged to look it up if you&amp;rsquo;re curious). For now just remember the difference between &lt;code&gt;.&lt;/code&gt; and the &lt;code&gt;..&lt;/code&gt; special path.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;..&lt;/code&gt; (two full stops): The directory above the current one. If you keep running &lt;code&gt;cd ..&lt;/code&gt; you end up at &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-&lt;/code&gt; (dash): The previous directory you &lt;code&gt;cd&lt;/code&gt;-ed into.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Navigate to the home directory of the current user&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ~
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# An even easier shortcut for &amp;#39;cd ~&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Navigate to the highest level directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd /
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Navigate to Documents within your home directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ~/Documents
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Navigate to current directory (~/Documents - does nothing)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd .
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Navigate up one from Documents, i.e. your home directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ..
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Navigates back to ~/Documents&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd -
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="ls-see-the-contents-of-the-current-directory"&gt;
ls: See the contents of the current directory
&lt;a class="heading-link" href="#ls-see-the-contents-of-the-current-directory"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ls&lt;/code&gt; (&amp;ldquo;List&amp;rdquo;) command is useful for seeing what&amp;rsquo;s in the current directory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;README.md package.json package-lock.json public/ static/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Depending on your configuration files and directories may be coloured differently.&lt;/p&gt;
&lt;h3 id="echo-print-to-screen"&gt;
echo: Print to screen
&lt;a class="heading-link" href="#echo-print-to-screen"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;You can use the &lt;code&gt;echo&lt;/code&gt; command to print to the terminal. On its own this isn&amp;rsquo;t very interesting, but it is very powerful when combined with other commands and variables.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Read the USER environment variable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;My name is &lt;/span&gt;$USER&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;My name is kinbiko
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="-and--create-file-with-command-output"&gt;
&amp;gt; and &amp;raquo;: Create file with command output
&lt;a class="heading-link" href="#-and--create-file-with-command-output"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;We can take the above command, and redirect the output to a file using &lt;code&gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;My name is &lt;/span&gt;$USER&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &amp;gt; echo-example.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This won&amp;rsquo;t print the output anymore as we&amp;rsquo;ve told Bash to redirect output to the file &lt;code&gt;echo-example.txt&lt;/code&gt;. Open the file in a text editor to verify that this is indeed the case.&lt;/p&gt;
&lt;p&gt;On the other hand, the &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; command will &lt;em&gt;append&lt;/em&gt; to the file you specify, whereas &amp;gt; will overwrite it entirely.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;My name is &lt;/span&gt;$USER&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; echo-example.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, the &lt;code&gt;echo-example.txt&lt;/code&gt; file will contain the same line twice.&lt;/p&gt;
&lt;p&gt;Try the original command again, and verify that the file only has one line.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;My name is &lt;/span&gt;$USER&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &amp;gt; echo-example.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="rm-remove-file"&gt;
rm: Remove file
&lt;a class="heading-link" href="#rm-remove-file"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s remove the file we just created in the above example.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls &lt;span style="color:#75715e"&gt;# Verify that you see the file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rm echo-example.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls &lt;span style="color:#75715e"&gt;# Verify that the file is gone&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There, gone. This is a very powerful command, and won&amp;rsquo;t simply move things to your Rubbish Bin or similar if your operating system supports this feature. The file is gone forever. Make sure you only run &lt;code&gt;rm&lt;/code&gt; on files you are absolutely sure you want to get rid off.&lt;/p&gt;
&lt;h3 id="mkdir-create-a-directory"&gt;
mkdir: Create a directory
&lt;a class="heading-link" href="#mkdir-create-a-directory"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;To create a directory use the &lt;code&gt;mkdir&lt;/code&gt; (&amp;ldquo;make directory&amp;rdquo;) command.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir repos
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls &lt;span style="color:#75715e"&gt;# Verify that a directory called &amp;#39;repos&amp;#39; has been created&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="rmdir-remove-directory"&gt;
rmdir: Remove directory
&lt;a class="heading-link" href="#rmdir-remove-directory"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;To remove a directory we use &lt;code&gt;rmdir&lt;/code&gt; (&amp;ldquo;Remove directory&amp;rdquo;). Let&amp;rsquo;s remove the directory we created above.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls &lt;span style="color:#75715e"&gt;# Verify that you see a directory called &amp;#39;repos&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rmdir repos
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls &lt;span style="color:#75715e"&gt;# Verify that this directory is no longer there&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note, this command does not work if the directory is not empty. This is a measure to prevent you from shooting yourself in the foot. &lt;code&gt;rmdir&lt;/code&gt;, like &lt;code&gt;rm&lt;/code&gt; are powerful commands. Once deleted, you won&amp;rsquo;t get it back.&lt;/p&gt;
&lt;p&gt;There is of course a way of deleting a directory along with all its contents, but this is a &lt;em&gt;ridiculously powerful command&lt;/em&gt; (to the extent that it&amp;rsquo;s the centre of many geeky jokes and memes) and therefore will not be covered in this beginner&amp;rsquo;s article.&lt;/p&gt;
&lt;h3 id="cp-copy-file"&gt;
cp: Copy file
&lt;a class="heading-link" href="#cp-copy-file"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;To copy a file in Bash we use the &lt;code&gt;cp&lt;/code&gt; command with two arguments: The first is the path to the file we want to copy, and the second is the path to the file want to create as a copy.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;test&amp;#34;&lt;/span&gt; &amp;gt; example.txt &lt;span style="color:#75715e"&gt;# Create a file called example.txt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp example ../example-in-directory-above.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls &lt;span style="color:#75715e"&gt;# Should only see one example file here, the original `example.txt`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ..
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls &lt;span style="color:#75715e"&gt;# Should only see one example file here, the copied `example-in-directory-above.txt`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Verify that these files do in fact have the same contents.&lt;/p&gt;
&lt;h3 id="mv-move-and-rename-file-or-directory"&gt;
mv: Move and rename file or directory
&lt;a class="heading-link" href="#mv-move-and-rename-file-or-directory"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;In Bash moving files and renaming files are the same thing. Intuitively, this can be thought of as &amp;rsquo;editing the path of a file&amp;rsquo;.
Moving files is done with the &lt;code&gt;mv&lt;/code&gt; (&amp;ldquo;Move&amp;rdquo;) command, which similar to &lt;code&gt;cp&lt;/code&gt; takes two arguments: the first being the path to the file to move, and the second is the new path the file should have.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;example&amp;#34;&lt;/span&gt; &amp;gt; example.txt &lt;span style="color:#75715e"&gt;# Create an example file to move&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mv example.txt ~/test.txt &lt;span style="color:#75715e"&gt;# Move the example file to the home directory, and rename it to test.txt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;mv&lt;/code&gt; works on both files and directories.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir example-dir
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mv example-dir ~/test-dir &lt;span style="color:#75715e"&gt;# Move the example directory to the home directory, and rename it to test-dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="clear-remove-old-output-and-commands-from-your-terminal-window"&gt;
clear: Remove old output and commands from your terminal window
&lt;a class="heading-link" href="#clear-remove-old-output-and-commands-from-your-terminal-window"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;This one is one of the commands I run the most often. I like working with a clean screen so that the outputs I see on my screen is relevant to the current context I&amp;rsquo;m working wtih. To achieve this I run &lt;code&gt;clear&lt;/code&gt; between each contextually different sets of commands that I run.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd repos
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir awesome-repo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd awesome-repo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;# Awesome Repo&amp;#34;&lt;/span&gt; &amp;gt; README.md
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# more work...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;clear
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd &lt;span style="color:#75715e"&gt;# Return to home directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd Downloads
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rm img3514.jpeg &lt;span style="color:#75715e"&gt;# Delete a picture I had in my Downloads directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="conclusion"&gt;
Conclusion
&lt;a class="heading-link" href="#conclusion"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;As you get more used to the command line you&amp;rsquo;ll pick up more and more commands and Bash tricks. Perhaps you also find new ways of doing things that you prefer over the ones listed here. That being said, you should now know your basic commands and learning new commands should be easier in the future.&lt;/p&gt;</description></item><item><title>My Shiniest Vim Gems</title><link>https://kinbiko.com/posts/2017-12-09-my-shiniest-vim-gems/</link><pubDate>Sat, 16 Dec 2017 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2017-12-09-my-shiniest-vim-gems/</guid><description>&lt;p&gt;Vim is highly customisable, and I recommend everyone tailor their config
according to their own preferences. That being said, here are some bits I think
people may want to steal from my &lt;code&gt;.vimrc&lt;/code&gt;. I tried to avoid the more common
options you&amp;rsquo;d find in similar articles written by others, such as enabling line
numbers, &lt;code&gt;tpope&lt;/code&gt;&amp;rsquo;s surround plugin, or sane backspacing, and focus on the
lesser-known tricks and settings.&lt;/p&gt;
&lt;h2 id="general-settings"&gt;
General settings
&lt;a class="heading-link" href="#general-settings"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;h4 id="highlight-the-current-column"&gt;
Highlight the current column
&lt;a class="heading-link" href="#highlight-the-current-column"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;Immediately find exactly where your cursor is, using &lt;code&gt;set cursorcolumn&lt;/code&gt;. This
will highlight the column you&amp;rsquo;re currently on, similar to how you might also do
&lt;code&gt;set cursorline&lt;/code&gt; to highlight the row (line). I have &lt;code&gt;cursorline&lt;/code&gt; disabled as I
rely on by color scheme&amp;rsquo;s highlighting of the line number in the gutter
instead.&lt;/p&gt;
&lt;h4 id="make-whitespace-visible"&gt;
Make whitespace visible
&lt;a class="heading-link" href="#make-whitespace-visible"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;Show invisible characters using &lt;code&gt;set listchars=tab:&amp;gt;-,trail:·&lt;/code&gt; This means that
tabs should be shown as &lt;code&gt;&amp;gt;&lt;/code&gt; followed by a stream of &lt;code&gt;-&lt;/code&gt; characters. The number
of &lt;code&gt;-&lt;/code&gt; characters depends on how many spaces a tab should be as defined by your
&lt;code&gt;tabstop&lt;/code&gt; setting. Any trailing whitespace shows up as an interpunct (·). To
get this working you&amp;rsquo;ll need to follow the above config with &lt;code&gt;set list&lt;/code&gt;. Pretty
rock &amp;rsquo;n roll.&lt;/p&gt;
&lt;h4 id="sane-line-joins"&gt;
Sane line joins
&lt;a class="heading-link" href="#sane-line-joins"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;You&amp;rsquo;re probably aware that &lt;code&gt;J&lt;/code&gt; in normal mode tries to join the next line with
your current line removing the newline. This tends to work in a very awkward
manner with comments. Normally, pressing &lt;code&gt;JJ&lt;/code&gt; on the first line of:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * Creates a User entity using the default parameters.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;results in&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/** * Creates a User entity using the default parameters. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, this inconvenience has been fixed as an optional setting as of version
7.3.541, and can be enabled as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;:&lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; &amp;gt; &lt;span style="color:#ae81ff"&gt;703&lt;/span&gt; || &lt;span style="color:#a6e22e"&gt;v&lt;/span&gt;:&lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; == &lt;span style="color:#ae81ff"&gt;703&lt;/span&gt; &amp;amp;&amp;amp; &lt;span style="color:#a6e22e"&gt;has&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;patch541&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;set&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;formatoptions&lt;/span&gt;+=&lt;span style="color:#a6e22e"&gt;j&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, assuming your version of Vim is relatively recent, the same example will
be formatted as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/** Creates a User entity using the default parameters. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Much better.&lt;/p&gt;
&lt;h4 id="highlight-ugly-code"&gt;
Highlight ugly code:
&lt;a class="heading-link" href="#highlight-ugly-code"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;I don&amp;rsquo;t like excessively long lines of code (120+ in most languages), and I
don&amp;rsquo;t like trailing whitespace. You can easily mark these using the following
two commands:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;match&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ErrorMsg&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;\%&amp;gt;120v.\+&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;match&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ErrorMsg&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;\s\+$&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="plugins"&gt;
Plugins
&lt;a class="heading-link" href="#plugins"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I like my plugins, and these are my favourites, in no particular order.&lt;/p&gt;
&lt;h4 id="terminus"&gt;
&lt;a href="https://github.com/wincent/terminus" class="external-link" target="_blank" rel="noopener"&gt;Terminus&lt;/a&gt;
&lt;a class="heading-link" href="#terminus"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;This plugin is basically enables stuff you probably want, but don&amp;rsquo;t bother to
look for individually: Mouse support, different cursor shapes for insert,
normal and replace mode, and paste convenience.&lt;/p&gt;
&lt;h4 id="fzfvim"&gt;
&lt;a href="https://github.com/junegunn/fzf.vim" class="external-link" target="_blank" rel="noopener"&gt;fzf.vim&lt;/a&gt;
&lt;a class="heading-link" href="#fzfvim"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;This plugin assumes you have &lt;a href="https://github.com/junegunn/fzf" class="external-link" target="_blank" rel="noopener"&gt;fzf&lt;/a&gt; installed
locally, as you should. Chances are you&amp;rsquo;re already using it, but it&amp;rsquo;s by far
the best fuzzy finder around. More on how I use it for quick lookups in the
mappings section below.&lt;/p&gt;
&lt;h4 id="ag"&gt;
&lt;a href="https://github.com/rking/ag.vim" class="external-link" target="_blank" rel="noopener"&gt;Ag&lt;/a&gt;
&lt;a class="heading-link" href="#ag"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;For what &lt;code&gt;fzf&lt;/code&gt; can&amp;rsquo;t handle, i.e. text-inside-file search. Assumes you have
&lt;a href="https://github.com/ggreer/the_silver_searcher" class="external-link" target="_blank" rel="noopener"&gt;The Silver Searcher&lt;/a&gt;. Faster
than &lt;code&gt;ack&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="easymotion"&gt;
&lt;a href="https://github.com/easymotion/vim-easymotion" class="external-link" target="_blank" rel="noopener"&gt;EasyMotion&lt;/a&gt;
&lt;a class="heading-link" href="#easymotion"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;Super easy navigation to anywhere in the buffer. Similar to the &lt;code&gt;f&lt;/code&gt; option in
the Vimium Google Chrome extension.&lt;/p&gt;
&lt;h4 id="tabular"&gt;
&lt;a href="https://github.com/tab" class="external-link" target="_blank" rel="noopener"&gt;Tabular&lt;/a&gt;
&lt;a class="heading-link" href="#tabular"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;This plugin allows you to align a block of text according to a pattern. Suppose
for example we have the following annoyingly-formatted JSON objects:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#f92672"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;River Tam&amp;#34;&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;#34;skills&amp;#34;&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#34;Cockney accent&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Ability to kill you with her brain&amp;#34;&lt;/span&gt;], &lt;span style="color:#f92672"&gt;&amp;#34;Age&amp;#34;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#f92672"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Jayne Cobb&amp;#34;&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;#34;skills&amp;#34;&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#34;Extreme confidence&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Naming guns&amp;#34;&lt;/span&gt;], &lt;span style="color:#f92672"&gt;&amp;#34;age&amp;#34;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;33&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You know that there&amp;rsquo;s an inconsistency somewhere in here, but you can&amp;rsquo;t spot it
by looking at how the code is formatted right now. Run &lt;code&gt;Tabular /,&lt;/code&gt; to align by
commas and you quickly spot that the key for age is inconsistently formatted.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#f92672"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;River Tam&amp;#34;&lt;/span&gt; , &lt;span style="color:#f92672"&gt;&amp;#34;skills&amp;#34;&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#34;Cockney accent&amp;#34;&lt;/span&gt; , &lt;span style="color:#e6db74"&gt;&amp;#34;Ability to kill you with her brain&amp;#34;&lt;/span&gt;] , &lt;span style="color:#f92672"&gt;&amp;#34;Age&amp;#34;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#f92672"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Jayne Cobb&amp;#34;&lt;/span&gt; , &lt;span style="color:#f92672"&gt;&amp;#34;skills&amp;#34;&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#34;Extreme confidence&amp;#34;&lt;/span&gt; , &lt;span style="color:#e6db74"&gt;&amp;#34;Naming guns&amp;#34;&lt;/span&gt;] , &lt;span style="color:#f92672"&gt;&amp;#34;age&amp;#34;&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;33&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="prettier"&gt;
&lt;a href="https://github.com/prettier/vim-prettier" class="external-link" target="_blank" rel="noopener"&gt;Prettier&lt;/a&gt;
&lt;a class="heading-link" href="#prettier"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;I remember spending a bit more time than I&amp;rsquo;d like trying to get this up and
running, but, really, once you try
&lt;a href="https://github.com/prettier/prettier" class="external-link" target="_blank" rel="noopener"&gt;prettier&lt;/a&gt; you won&amp;rsquo;t write
JavaScript/Markdown the same way again. It is such a relief not having to worry
about formatting ever again.&lt;/p&gt;
&lt;h4 id="vim-go"&gt;
&lt;a href="https://github.com/fatih/vim-go" class="external-link" target="_blank" rel="noopener"&gt;vim-go&lt;/a&gt;
&lt;a class="heading-link" href="#vim-go"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;There are many plugins designed to make certain programming languages easier to
write in. Nobody has quite managed to get the full immersion as this plugin has
though. Golang comes with the &lt;code&gt;go&lt;/code&gt; command-line tool, which has a lot of
features built-in that in other languages would be third party tools. For
example formatting, organising imports, running tests etc. This plugin handles
all of that, and then some(Going to declarations, adding new movement objects,
going to alternative files). I like Go as a language, but sometimes I want to
write Go just so I can use this plugin.&lt;/p&gt;
&lt;h2 id="mappings"&gt;
Mappings
&lt;a class="heading-link" href="#mappings"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;h3 id="normal-mode"&gt;
Normal mode
&lt;a class="heading-link" href="#normal-mode"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;h4 id="search-the-git-repository-for-filename-with-"&gt;
Search the Git repository for filename with ?
&lt;a class="heading-link" href="#search-the-git-repository-for-filename-with-"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;nnoremap&lt;/span&gt; ? :&lt;span style="color:#a6e22e"&gt;GFiles&lt;/span&gt;&amp;lt;&lt;span style="color:#a6e22e"&gt;CR&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This mapping relies on &lt;code&gt;GFiles&lt;/code&gt; from &lt;code&gt;fzf.vim&lt;/code&gt;, and saves a lot of time. Much
more efficient than &lt;code&gt;ctrl+p&lt;/code&gt; or &lt;code&gt;cmd+t&lt;/code&gt;, and since it&amp;rsquo;s only looking for files
that aren&amp;rsquo;t &lt;code&gt;.gitignored&lt;/code&gt; you don&amp;rsquo;t get all the clutter you might get with
&lt;code&gt;node_modules&lt;/code&gt; or &lt;code&gt;build/&lt;/code&gt; directories.&lt;/p&gt;
&lt;h4 id="handle-git-hunks-with-ctrln-and-ctrlp-and-ctrlu"&gt;
Handle Git hunks with &lt;code&gt;&amp;lt;CTRL&amp;gt;n&lt;/code&gt; and &lt;code&gt;&amp;lt;CTRL&amp;gt;p&lt;/code&gt; and &lt;code&gt;&amp;lt;CTRL&amp;gt;u&lt;/code&gt;
&lt;a class="heading-link" href="#handle-git-hunks-with-ctrln-and-ctrlp-and-ctrlu"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;nnoremap&lt;/span&gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;-&lt;span style="color:#a6e22e"&gt;N&lt;/span&gt;&amp;gt; :&lt;span style="color:#a6e22e"&gt;GitGutterNextHunk&lt;/span&gt;&amp;lt;&lt;span style="color:#a6e22e"&gt;CR&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;nnoremap&lt;/span&gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;-&lt;span style="color:#a6e22e"&gt;P&lt;/span&gt;&amp;gt; :&lt;span style="color:#a6e22e"&gt;GitGutterPrevHunk&lt;/span&gt;&amp;lt;&lt;span style="color:#a6e22e"&gt;CR&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;nnoremap&lt;/span&gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;-&lt;span style="color:#a6e22e"&gt;U&lt;/span&gt;&amp;gt; :&lt;span style="color:#a6e22e"&gt;GitGutterUndoHunk&lt;/span&gt;&amp;lt;&lt;span style="color:#a6e22e"&gt;CR&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Relies on the &lt;a href="https://github.com/airblade/vim-gitgutter" class="external-link" target="_blank" rel="noopener"&gt;GitGutter&lt;/a&gt; plugin.
Moves to the next/previous hunk using &lt;code&gt;&amp;lt;CTRL&amp;gt;n&lt;/code&gt;/&lt;code&gt;&amp;lt;CTRL&amp;gt;p&lt;/code&gt;, and when the cursor
is on a hunk, &lt;code&gt;&amp;lt;CTRL&amp;gt;u&lt;/code&gt; will revert that hunk. Safer than doing it from the
command line as your revert is undoable as it&amp;rsquo;s in your Git undo tree.&lt;/p&gt;
&lt;h4 id="easy-peasy-in-file-navigation-with-enter-and-backspace"&gt;
Easy-peasy in-file navigation with Enter and Backspace
&lt;a class="heading-link" href="#easy-peasy-in-file-navigation-with-enter-and-backspace"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;Have you noticed that both the enter key and the backspace key are basically
unused in normal mode. They just go down one line or back one character
respectively. Well, we&amp;rsquo;ve got &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;l&lt;/code&gt; for that, so let&amp;rsquo;s rebind them to
move a little further (one paragraph):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;nnoremap&lt;/span&gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;BS&lt;/span&gt;&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;onoremap&lt;/span&gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;BS&lt;/span&gt;&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;vnoremap&lt;/span&gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;BS&lt;/span&gt;&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;nnoremap&lt;/span&gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;expr&lt;/span&gt;&amp;gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;CR&lt;/span&gt;&amp;gt; &lt;span style="color:#a6e22e"&gt;empty&lt;/span&gt;(&amp;amp;&lt;span style="color:#a6e22e"&gt;buftype&lt;/span&gt;) ? &lt;span style="color:#e6db74"&gt;&amp;#39;}&amp;#39;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;CR&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;onoremap&lt;/span&gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;expr&lt;/span&gt;&amp;gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;CR&lt;/span&gt;&amp;gt; &lt;span style="color:#a6e22e"&gt;empty&lt;/span&gt;(&amp;amp;&lt;span style="color:#a6e22e"&gt;buftype&lt;/span&gt;) ? &lt;span style="color:#e6db74"&gt;&amp;#39;}&amp;#39;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;CR&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;vnoremap&lt;/span&gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;CR&lt;/span&gt;&amp;gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;onoremap&lt;/code&gt; basically ensures that the paragraph word object is also
respected, E.g. when you type &lt;code&gt;d&amp;lt;CR&amp;gt;&lt;/code&gt; you delete from the current position to
the next paragraph. The empty check is to ensure that you can still use the
enter key in Quickfix windows as you would normally.&lt;/p&gt;
&lt;h4 id="move-precisely-to-any-position-in-the-visible-buffer"&gt;
Move precisely to any position in the visible buffer
&lt;a class="heading-link" href="#move-precisely-to-any-position-in-the-visible-buffer"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;nmap&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;F&lt;/span&gt; &amp;lt;&lt;span style="color:#a6e22e"&gt;Plug&lt;/span&gt;&amp;gt;(&lt;span style="color:#a6e22e"&gt;easymotion&lt;/span&gt;-&lt;span style="color:#a6e22e"&gt;prefix&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;References the EasyMotion plugin mentioned above.
Hit &lt;code&gt;F&lt;/code&gt; followed by the value of the character you want to move to. One of two
things will happen. You will either be taken to where you want to go (usually
for rare characters) or you&amp;rsquo;ll be shown a map of all of these characters
currently visible, with the keys you need to hit to navigate there. This is one
of those tools that&amp;rsquo;s really easy to understand once you start using it, but
hard to explain in text. Try it out! You won&amp;rsquo;t be sorry.&lt;/p&gt;
&lt;h3 id="other-mappings"&gt;
Other mappings
&lt;a class="heading-link" href="#other-mappings"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h3&gt;
&lt;h4 id="keep-selected-text-selected-when-fixing-indentation"&gt;
Keep selected text selected when fixing indentation
&lt;a class="heading-link" href="#keep-selected-text-selected-when-fixing-indentation"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;vnoremap&lt;/span&gt; &amp;lt; &amp;lt;&lt;span style="color:#a6e22e"&gt;gv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;vnoremap&lt;/span&gt; &amp;gt; &amp;gt;&lt;span style="color:#a6e22e"&gt;gv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Self explanatory, but did you notice that &lt;code&gt;gv&lt;/code&gt; takes you to the last visually
selected text?&lt;/p&gt;
&lt;h4 id="make-quotes-and-square-brackets-into-movements"&gt;
Make quotes and square brackets into movements
&lt;a class="heading-link" href="#make-quotes-and-square-brackets-into-movements"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;onoremap&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;q&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;onoremap&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Q&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;onoremap&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ia&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;onoremap&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aa&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This simplifies actions such as &lt;code&gt;di&amp;quot;&lt;/code&gt; to &lt;code&gt;dQ&lt;/code&gt;, and &lt;code&gt;di]&lt;/code&gt; to &lt;code&gt;dia&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;
Conclusion
&lt;a class="heading-link" href="#conclusion"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;This of course reflects only some of my &lt;code&gt;.vimrc&lt;/code&gt; at this point in time. Head
over to my &lt;a href="https://github.com/kinbiko/dotfiles" class="external-link" target="_blank" rel="noopener"&gt;dotfiles repository&lt;/a&gt; to browse
my current dotfiles, among them my &lt;code&gt;.vimrc&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Modern Approaches to Dealing with Legacy Code (x-post)</title><link>https://kinbiko.com/posts/2017-08-15-software-engineering-legacy/</link><pubDate>Tue, 15 Aug 2017 00:00:00 +0000</pubDate><guid>https://kinbiko.com/posts/2017-08-15-software-engineering-legacy/</guid><description>&lt;p&gt;I wrote an article on how to manage your legacy systems using modern tools and techniques on my work blog. Please &lt;a href="https://blog.bugsnag.com/modern-approach-to-legacy-code/" class="external-link" target="_blank" rel="noopener"&gt;check it out&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Sentiment Analysis Workshop</title><link>https://kinbiko.com/talks/2017-04-26-sentiment-analysis-workshop/</link><pubDate>Wed, 26 Apr 2017 00:00:00 +0000</pubDate><guid>https://kinbiko.com/talks/2017-04-26-sentiment-analysis-workshop/</guid><description>&lt;p&gt;Learn some basics of sentiment analysis in Python,
using both rule-based sentiment analysis and ML based sentiment analysis.&lt;/p&gt;</description></item><item><title>Calendar</title><link>https://kinbiko.com/utils/calendar/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kinbiko.com/utils/calendar/</guid><description/></item><item><title>Opportunities</title><link>https://kinbiko.com/opportunities/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kinbiko.com/opportunities/</guid><description/></item><item><title>Roger Guldbrandsen</title><link>https://kinbiko.com/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kinbiko.com/about/</guid><description>&lt;h1 id="hello-世界"&gt;
Hello 世界
&lt;a class="heading-link" href="#hello-%e4%b8%96%e7%95%8c"&gt;
&lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
&lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
&lt;/a&gt;
&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;m a software guy based in &lt;i class="fa-solid fa-location-dot"&gt;&lt;/i&gt; &lt;strong&gt;Osaka, Japan&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I speak 🇬🇧 English, 🇯🇵 Japanese, and 🇳🇴 Norwegian, and as for software technologies I&amp;rsquo;m an expert in distrubuted systems of &lt;i class="fa-solid fa-cubes"&gt;&lt;/i&gt; &lt;strong&gt;microservices&lt;/strong&gt; written in &lt;i class="fa-brands fa-golang"&gt;&lt;/i&gt; &lt;strong&gt;Go&lt;/strong&gt; or &lt;i class="fa-brands fa-java"&gt;&lt;/i&gt; &lt;strong&gt;Java&lt;/strong&gt;, running in &lt;i class="fa-brands fa-docker"&gt;&lt;/i&gt; &lt;strong&gt;Kubernetes&lt;/strong&gt; clusters.
I&amp;rsquo;m also familiar with &lt;i class="fa-brands fa-js"&gt;&lt;/i&gt; &lt;strong&gt;JavaScript&lt;/strong&gt; and &lt;i class="fa-brands fa-python"&gt;&lt;/i&gt; &lt;strong&gt;Python&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I love teaching and mentoring aspiring and junior engineers, and am open to speaking or teaching opportunities at Japanese universities, as well as speaking at technical conferences and meetups.
I&amp;rsquo;m also interested in contributing to projects that make a real difference.
Whether that&amp;rsquo;s benefiting humanity, helping dogs, or protecting the environment.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re aware of any teaching or speaking opportunities, or any projects you think I might be interested in, please don&amp;rsquo;t hesitate to contact me via e-mail at &lt;a href="mailto:contact-kinbiko@pm.me" &gt;contact-kinbiko@pm.me&lt;/a&gt; &lt;i class="fa-solid fa-envelope"&gt;&lt;/i&gt;&lt;/p&gt;</description></item><item><title>Utils</title><link>https://kinbiko.com/utils/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kinbiko.com/utils/</guid><description/></item></channel></rss>