<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>bryce.is/writing/code</title>
  <subtitle>My name is Bryce. I build software. This website is a collection of my personal projects and writings.</subtitle>
  <link href="https://bryce.is/feed.xml" rel="self"/>
  <link href="https://bryce.is/writing/code"/>
  <updated>2026-02-04T09:00:00-00:00</updated>
  <id>https://bryce.is/writing/code</id>
  <author>
    <name>Bryce Neal</name>
    <email>brycedneal@gmail.com</email>
  </author>
  
  <entry>
    <title>3 Go Gotchas</title>
    <link href="https://bryce.is/writing/code/2015/11/01/3-go-gotchas.html"/>
    <updated>2015-11-01T10:00:00-00:00</updated>
    <id>https://bryce.is/writing/code/2015/11/01/3-go-gotchas.html</id>
    <content type="html">&lt;p class=&quot;markdown-paragraph&quot;&gt;Lately I&#39;ve been doing more work in the &lt;a href=&quot;https://golang.org/&quot;&gt;Go&lt;/a&gt; programming language. Today I thought I would share three &amp;quot;gotchas&amp;quot; that caught me off guard, or otherwise produced results that I would not have expected in my work with Go.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;1. The range clause&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The range clause is very convenient. It allows you to iterate over a slice or map with two variables which represent the index and the value of each item. For example:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;range&lt;/span&gt; mySlice &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;index: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;value: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;However, something notable is happening under the hood. Let&#39;s see  more complex example:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; Foo &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    bar &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    list &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;Foo&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;    list2 &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Foo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;range&lt;/span&gt; list &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        list2&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;value&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;    fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list2&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; list2&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; list2&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;In this example we are doing a few things.&lt;/p&gt;
&lt;ol class=&quot;markdown-ol&quot;&gt;
&lt;li class=&quot;markdown-li&quot;&gt;We are creating a slice of &lt;code class=&quot;markdown-code&quot;&gt;Foo&lt;/code&gt; structs called &lt;em&gt;list&lt;/em&gt;.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;We are defining a second slice of pointers to Foo structs called &lt;em&gt;list2&lt;/em&gt;.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;We iterate through each struct in &lt;em&gt;list&lt;/em&gt; in order to assign its pointer to the corresponding index in &lt;em&gt;list2&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;So therefore you might expect the output of the above code to be the following:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;A&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;B&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;C&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;A&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;B&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;C&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;However, this is not what is happening. Let&#39;s take a look at the output of this code:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;A&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;B&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;C&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;C&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;C&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;C&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The first line is as expected. These are the structs we initially created in &lt;em&gt;list&lt;/em&gt;, but the second line is unexpected. It looks like we are printing out a pointer to the last struct in the list three times. But why is this happening ?&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The culprit is the range clause.&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;range&lt;/span&gt; list &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    list2&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;value&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Here&#39;s the problem: &lt;em&gt;Go uses a copy of the value instead of the value itself within a range clause.&lt;/em&gt; So when we take the pointer of &lt;code class=&quot;markdown-code&quot;&gt;value&lt;/code&gt;, we&#39;re actually taking the pointer of a &lt;strong&gt;copy&lt;/strong&gt; of the value. This copy gets reused throughout the range clause, which leaves our &lt;em&gt;list2&lt;/em&gt; slice full of three references to the same pointer (the copy pointer).&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;According to the Go reference manual, &amp;quot;The iteration values are assigned to the respective iteration variables as in an assignment statement.&amp;quot; So effectively you can imagine the above range clause to be the same as writing:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; value Foo&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br&gt;    list2&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;value&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;In order to produce the output we expect, we should use the index to take a pointer to the actual value, instead of the copy.&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;range&lt;/span&gt; list &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    list2&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;2. The append built-in function&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Slices are primitive types in Go. In other languages you might reach for an Array where in Go you would reach for a Slice. Here&#39;s an example of how we might add a value to the end of an integer slice.&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;list &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;list &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [0 1 2 3]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;On the surface it seems to be similar to a &lt;code class=&quot;markdown-code&quot;&gt;push()&lt;/code&gt; array method, but slices are not quite arrays, and the built-in append function surprised me with its behavior under the hood. Have a look at the example below:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    a &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    b &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    c &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;baz&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;        &lt;br&gt;    fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;In this example we define a slice &lt;code class=&quot;markdown-code&quot;&gt;a&lt;/code&gt; of bytes with an initial value of &lt;code class=&quot;markdown-code&quot;&gt;[&amp;quot;foo&amp;quot;]&lt;/code&gt;. Next we append another slice &lt;code class=&quot;markdown-code&quot;&gt;[&amp;quot;bar&amp;quot;]&lt;/code&gt; to our initial slice &lt;code class=&quot;markdown-code&quot;&gt;a&lt;/code&gt;, and again we append another slice &lt;code class=&quot;markdown-code&quot;&gt;[&amp;quot;baz&amp;quot;]&lt;/code&gt; to our initial slice &lt;code class=&quot;markdown-code&quot;&gt;a&lt;/code&gt;. The output of the above snippet is:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;foo foobaz foobaz&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Whaaat? 😮 Shouldn&#39;t it be &lt;code class=&quot;markdown-code&quot;&gt;foo foobar foobaz&lt;/code&gt; ?&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;In order to understand what&#39;s going on here we have to understand what a slice really is. A slice is a descriptor which consists of three components:&lt;/p&gt;
&lt;ol class=&quot;markdown-ol&quot;&gt;
&lt;li class=&quot;markdown-li&quot;&gt;A pointer to an underlying array - that is, one allocated by Go which you don&#39;t have direct access to.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;The capacity of said underlying array.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;The effective length of the slice.&lt;/li&gt;
&lt;/ol&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;So what&#39;s really happening ? &lt;strong&gt;Go will reuse the same underlying array in&lt;/strong&gt; &lt;code class=&quot;markdown-code&quot;&gt;append()&lt;/code&gt; &lt;strong&gt;if it can do so without resizing the underlying array.&lt;/strong&gt; So all three of these structs are referencing the exact same array in memory. The only practical difference is their length value which in the case of &lt;code class=&quot;markdown-code&quot;&gt;a&lt;/code&gt; is &lt;strong&gt;3&lt;/strong&gt;, and in the case of &lt;code class=&quot;markdown-code&quot;&gt;b&lt;/code&gt; and &lt;code class=&quot;markdown-code&quot;&gt;c&lt;/code&gt; is &lt;strong&gt;6&lt;/strong&gt;.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Keep in mind, Go will only reuse the same underlying array if the length of the newly created slice is less than or equal to the capacity of the initial slice.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;It&#39;s important to understand what is happening under the hood when using some of the built-in slice functions. For more info, Robe Pike wrote a very helpful &lt;a href=&quot;https://blog.golang.org/slices&quot;&gt;blog post&lt;/a&gt; which goes into a lot of useful details around slices.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;3. Variable shadowing&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;When people first look at Go code for the first time, one of the first things they ask is &lt;em&gt;&amp;quot;What is that := operator for?&amp;quot;&lt;/em&gt;. Well, as you know, it&#39;s a shorthand variable declaration operator. It&#39;s used for both declaring and setting the value of a variable. The type is implicitly declared. This is very convenient, but can lead to some problems if you aren&#39;t careful. Specifically I&#39;m talking about variable shadowing. This is something that has bitten me in particular, because I have been programming almost exclusively in es5 javascript for the last two years where there is no block-level scoping.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Check this out:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    list &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        list&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token function&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;        fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;    fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; errors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Nothing to repeat!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;    list &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; list&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;nil&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;This is somewhat of a contrived example, so bear with me because I think it illustrates the point well. The run down of this snippet is as follows:&lt;/p&gt;
&lt;ol class=&quot;markdown-ol&quot;&gt;
&lt;li class=&quot;markdown-li&quot;&gt;We create a slice of strings, &lt;code class=&quot;markdown-code&quot;&gt;list&lt;/code&gt;.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;We enter a for loop.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;The for loop calls a function &lt;code class=&quot;markdown-code&quot;&gt;repeat()&lt;/code&gt; which returns a new slice, and an error.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;We break out of the for loop, and we print the value of &lt;code class=&quot;markdown-code&quot;&gt;list&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;You might expect the output here to be:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;a b c a b c&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;a b c a b c&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;but in fact, it is:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;a b c a b c&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;a b c&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Because we use the shorthand variable declaration operator, we are actually redeclaring the &lt;code class=&quot;markdown-code&quot;&gt;list&lt;/code&gt; variable inside of the scope of the for loop. This is awkward, because the second variable &lt;code class=&quot;markdown-code&quot;&gt;err&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; a new variable which we want to declare. We can fix this by changing the first few lines within the for block to:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; err &lt;span class=&quot;token builtin&quot;&gt;error&lt;/span&gt;&lt;br&gt;list&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; err &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;duplicate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;One way to catch these problems early is by taking advantage of the &lt;code class=&quot;markdown-code&quot;&gt;go vet&lt;/code&gt; tool. It has an option &lt;code class=&quot;markdown-code&quot;&gt;-shadow&lt;/code&gt; which can help to detect issues with variable shadowing.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;There is a good blog post called &lt;a href=&quot;http://www.qureet.com/blog/golang-beartrap/&quot;&gt;The Golang Beartrap&lt;/a&gt; that talks more in detail about variable shadowing.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Summary&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Go is a great language, and once you understand its quirks it can be a real pleasure to work in. I really appreciate the fantastic tooling, and readability of the language. Good luck, and happy gophering! 😄&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Getting started with mdb_v8</title>
    <link href="https://bryce.is/writing/code/2016/02/06/getting-started-with-mdb_v8.html"/>
    <updated>2016-02-06T10:00:00-00:00</updated>
    <id>https://bryce.is/writing/code/2016/02/06/getting-started-with-mdb_v8.html</id>
    <content type="html">&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;img src=&quot;https://bryce.is/assets/mdb-v8-0.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;!-- Excerpt Start --&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Did you know you can inspect your node application&#39;s memory without instrumenting your code? It&#39;s possible using a tool called mdb_v8. With mdb_v8 we can produce a core dump of a running node process, and then later inspect the memory at the time the core dump was generated. This leads to some powerful postmortem debugging capabilities.&lt;/p&gt;
&lt;!-- Excerpt End --&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;In this post I&#39;m going to walk you through setting up mdb_v8 locally so that you can inspect your node application&#39;s memory. Recently I went through this exercise myself and realized there was no good guide to do so. I decided to document the process and post it here.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The steps were going work through are as follows:&lt;/p&gt;
&lt;ol class=&quot;markdown-ol&quot;&gt;
&lt;li class=&quot;markdown-li&quot;&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Generate a core dump of our running node application&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Install a Solaris derivative in a VM&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Install mdb_v8, and run it against the core dump&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Be aware that this guide assumes a couple things about your workflow. First, that you are using a version of node at &lt;code class=&quot;markdown-code&quot;&gt;0.10&lt;/code&gt; or greater. At the time of this writing, all previous versions are no longer supported. Second, that your node service is running on a system where &lt;code class=&quot;markdown-code&quot;&gt;gcore&lt;/code&gt; is available, such as linux.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;A Solaris derivative is required to run mdb_v8. There are two post mortem debuggers that don&#39;t require Solaris, but they aren&#39;t as fully featured. These are &lt;a href=&quot;https://github.com/indutny/llnode&quot;&gt;llnode&lt;/a&gt; and &lt;a href=&quot;https://github.com/tjfontaine/lldb-v8&quot;&gt;lldb_v8&lt;/a&gt;. Alternatively, if instrumenting your code isn&#39;t an issue you may want to look into &lt;a href=&quot;https://github.com/bnoordhuis/node-heapdump&quot;&gt;node-heapdump&lt;/a&gt;.&lt;/p&gt;
&lt;h3 class=&quot;markdown-h3&quot;&gt;What is mdb_v8 anyways ?&lt;/h3&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;We can&#39;t talk about mdb_v8 without first talking about mdb. mdb is a low-level debugger developed by Sun for the Solaris operating system. What makes it unique is that is extremely extensible. It is possible to extend the tool with custom modules (&amp;quot;dmods&amp;quot;) for different contexts. This is exactly what Joyent has done with their mdb_v8 module. The mdb_v8 module adds a new set of commands instrumented specifically for the v8 javascript engine and node.js. It includes commands that allow you to inspect the application state, javascript frames, and javascript objects on the heap at the time the core dump was generated.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;It&#39;s worth emphasizing here that mdb &lt;em&gt;only&lt;/em&gt; works on Solaris derivatives. That is -- it won&#39;t run OS X, Windows, or Linux. More on this in a moment.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Generating a core dump&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;A core dump is a file which consists of the working memory of an application. It also typically contains some other metadata such as process registers. In linux generating a core dump of our node.js application manually is pretty straight forward. We just run the following command:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; gcore -o filename pid&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;This will produce a core dump file.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;You can also set up your node service to save a core dump when it crashes by using the &lt;code class=&quot;markdown-code&quot;&gt;--abort_on_uncaught_exception&lt;/code&gt; flag.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Installing mdb_v8&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;So mdb_v8 sounds great, right ? You will be able to inspect your application state, and find out where all of your sneaky memory leaks are hiding. Well, that&#39;s true, but as I mentioned above mdb_v8 only works on Solaris.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Therefore, we will use VirtualBox to install a Solaris derivative (OmniOS).&lt;/p&gt;
&lt;h3 class=&quot;markdown-h3&quot;&gt;Setting up VirtualBox with OmniOS&lt;/h3&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;If you don&#39;t already have VirtualBox installed, you can proceed to the downloads page to download the correct binary for your system and install it.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;a href=&quot;https://www.virtualbox.org/wiki/Downloads&quot;&gt;:arrow_down: Download VirtualBox&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;After you&#39;ve installed VirtualBox you will download a Solaris derivative. Here we will use OmniOS. Download the current/stable release under &amp;quot;From CD/iso&amp;quot;&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;a href=&quot;http://omnios.omniti.com/wiki.php/Installation&quot;&gt;:arrow_down: Download OmniOS&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Once you&#39;ve downloaded the image you can move back over to VirtualBox.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Select &amp;quot;Oracle Solaris 11&amp;quot;, and continue with everything else as the default.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;img src=&quot;https://bryce.is/assets/mdb-v8-1.png&quot; alt=&quot;Create the VM&quot;&gt;&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Once the VM is running, start it up and choose the OmniOS image that you downloaded above.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;img src=&quot;https://bryce.is/assets/mdb-v8-2.png&quot; alt=&quot;Create the VM&quot;&gt;&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Proceed through the installation process choosing your language, timezone, etc. Keep in mind that VirtualBox has a sandbox auto-resizing hard drive. It&#39;s fine to install the image on the &amp;quot;whole disk&amp;quot;. You can also ignore any warnings about kvm: No hardware support.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;img src=&quot;https://bryce.is/assets/mdb-v8-3.png&quot; alt=&quot;VM is installed&quot;&gt;&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;After you&#39;ve installed OmniOS, proceed to &amp;quot;Devices -&amp;gt; Optical drives -&amp;gt; Remove disk from virtual drive&amp;quot; in VirtualBox to unmount the disk. Finally, reboot the VM. You will be prompted to login once OmniOS starts up. The default login in OmniOS is &lt;code class=&quot;markdown-code&quot;&gt;root&lt;/code&gt; with no password.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Utilizing mdb_v8&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;If you&#39;ve made it this far you should be staring at an empty shell. There are still a few remaining steps before we can begin using mdb_v8. Those steps are as follows:&lt;/p&gt;
&lt;ol class=&quot;markdown-ol&quot;&gt;
&lt;li class=&quot;markdown-li&quot;&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;We need to be able to SSH into our VM from our local machine&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;We need to install the mdb_v8.so module for mdb&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;We need to SCP our core dump, and node.js binary to the virtual machine&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 class=&quot;markdown-h3&quot;&gt;SSHing into our VM&lt;/h3&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The first issue is that our VM doesn&#39;t have access to the local network. We need to enable this option in VirtualBox. We want to give our VM an internal IP that we can reach via SSH. We can do this by right clicking our VM in VirtualBox, and heading to the settings page. Here we will change our networking adapter from NAT to Bridged Adapter.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;img src=&quot;https://bryce.is/assets/mdb-v8-4.png&quot; alt=&quot;VM is installed&quot;&gt;&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The next step is that we need to enable DHCP in OmniOS. This way our VM can be assigned an IP address on the network. We do that by using a tool called &lt;code class=&quot;markdown-code&quot;&gt;ipadm&lt;/code&gt; to create an IP interface.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ipadm create-if e1000g0&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ipadm create-addr -T dhcp e1000g0/v4&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Now that we have created our IP interface we can configure our DNS resolution. Run these commands to add a nameserver.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;nameserver 8.8.8.8&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; /etc/resolv.conf&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; /etc/nsswitch.dns /etc/nsswitch.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Hurray. Now we have network connectivity. Now let&#39;s get our new local IP on the network by running ifconfig.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ifconfig&lt;/span&gt; e1000g0&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;This will show us our local network IP address (directly after the inet).&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;img src=&quot;https://bryce.is/assets/mdb-v8-5.png&quot; alt=&quot;VM is installed&quot;&gt;&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Even though we have the network IP address, we still won&#39;t be able to SSH into the machine. Why ? Well because by default OmniOS (and many distributions) don&#39;t allow you to SSH in as the root user. This is typically a security precaution. However, because we are just doing this to run mdb_v8 locally, we can enable this functionality.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;To allow us to SSH in as root we can edit the sshd_config&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/ssh/sshd_config&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;and scroll down to the line that says &lt;code class=&quot;markdown-code&quot;&gt;PermitRootLogin no&lt;/code&gt; and change it to &lt;code class=&quot;markdown-code&quot;&gt;PermitRootLogin yes&lt;/code&gt;. After this we want to restart the SSH daemon.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; svcadm restart SSH&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Now we should be able to SSH into our VM. Nice! On to the next step.&lt;/p&gt;
&lt;h3 class=&quot;markdown-h3&quot;&gt;Installing mdb_v8&lt;/h3&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Luckily, OmniOS comes with mdb installed by default, but it does not come with the mdb_v8 module. We need to manually install this. To do this we can simply use curl to download the binary.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Let&#39;s first create a working directory.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; ~/mdbv8&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; ~/mdbv8&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;You can first curl Joyent&#39;s manta service to find the latest version of mdb_v8.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; https://us-east.manta.joyent.com/Joyent_Dev/public/mdb_v8/latest &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cut&lt;/span&gt; -c &lt;span class=&quot;token number&quot;&gt;27&lt;/span&gt;-&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Run the following command below (replace &lt;code class=&quot;markdown-code&quot;&gt;{version}&lt;/code&gt; below with version you got from the above curl i.e. &amp;quot;v1.1.2&amp;quot;)&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; -O https://us-east.manta.joyent.com/Joyent_Dev/public/mdb_v8/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;version&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;/mdb_v8_amd64.so&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Great. Now we have everything we need to run mdb_v8.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Putting it all together&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The last and final step is to move over both our core dump file(s), and our node binary. (Don&#39;t have a core dump file ? See the beginning of this post for a snippet of how to use &lt;code class=&quot;markdown-code&quot;&gt;gcore&lt;/code&gt;.)&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;What&#39;s all this about a node binary ? Well, mdb_v8 will only work against the node binary that was running your node application at the time that the core dump was generated. You can download it directly from the node.js website provided you know the &lt;em&gt;exact&lt;/em&gt; version and build. The easiest way is to simply grab the node binary off of the machine where you took the core dump. Typically you can find the node binary by running &lt;code class=&quot;markdown-code&quot;&gt;which node&lt;/code&gt;, but if you&#39;re using something like nvm it may require a little bit more digging.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Provided you have downloaded the node binary and your core dump on your local machine, you can now SCP these files onto your VM.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scp&lt;/span&gt; ./node root@192.168.1.82:~/mdbv8&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scp&lt;/span&gt; ./my-dump.gcore root@192.168.1.82:~/mdbv8&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Now we can start the mdb_v8 debugger against our core dump and node binary.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; mdb ./node ./my-dump.gcore&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;This will drop us into the mdb shell. All we need to do now is to load the mdb_v8 module by executing:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;::load /root/mdbv8/mdb_v8_amd64.so&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;💥 Now we can proceed to run any of the mdb_v8 commands against our core dump.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I like to start my mdb_v8 search by listing all js objects in memory. Try it yourself by typing.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;::findjsobjects&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;For a list of useful mdb_v8 commands I recommend the official &lt;a href=&quot;https://github.com/joyent/mdb_v8/blob/master/docs/usage.md&quot;&gt;mdb_v8 usage guide&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I also found &lt;a href=&quot;https://gist.github.com/tjfontaine/9244374&quot;&gt;this&lt;/a&gt; gist by tjfontaine to be pretty helpful.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Summary&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;In this guide I&#39;ve walked you through generating core dumps, installing solaris locally, and setting up mdb_v8. Hopefully you will find that mdb_v8 is a very useful node.js debugging tool to have in your back pocket for postmortem debugging. Good luck plugging all your leaks! 🚱&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Debugging using system calls in Mac OS X</title>
    <link href="https://bryce.is/writing/code/2016/07/30/debugging-using-system-calls.html"/>
    <updated>2016-07-30T11:00:00-00:00</updated>
    <id>https://bryce.is/writing/code/2016/07/30/debugging-using-system-calls.html</id>
    <content type="html">&lt;p class=&quot;markdown-paragraph&quot;&gt;Today I want to talk about an issue I was having with UDP sockets in Go, and how I learned more about my program by making use of two tools that ship with Mac OS X called dtruss, and DTrace.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I do most of my programming on a Mac, and I have been working on a project written in Go which makes use of UDP sockets. When trying to add some unit tests to my code I decided to create one around reconnections. In my test I created two sockets on localhost with two different ports, read/wrote from them, closed them, and then repeated this several hundred times. Eventually I would receive a &amp;quot;bind: address already in use&amp;quot; error upon the creation a socket. I wondered, why was this happening if I was closing the sockets ?&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Understanding UDP in Go&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;In Go we can use the &lt;code class=&quot;markdown-code&quot;&gt;net.ListenPacket&lt;/code&gt; method to start listening for UDP packets on a given network address. This function returns a &lt;code class=&quot;markdown-code&quot;&gt;net.PacketConn&lt;/code&gt; interface.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;According to the Go documentation for &lt;code class=&quot;markdown-code&quot;&gt;PacketConn&lt;/code&gt;, the &lt;code class=&quot;markdown-code&quot;&gt;Close&lt;/code&gt; method should either close the connection, or return an error:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; PacketConn &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// Close closes the connection.&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;error&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;If this were true then why was I getting these EADDRINUSE errors ? Time to investigate 🔎 But first a brief recap on system calls.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;System calls&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Systems calls are the way your program interfaces with your operating system. In unix-based x86 systems specifically your compiled code will contain a software interrupt which is passed a value corresponding to a function in the kernel. In our case we were interested in two system calls; &lt;code class=&quot;markdown-code&quot;&gt;bind&lt;/code&gt; and &lt;code class=&quot;markdown-code&quot;&gt;close&lt;/code&gt;. &lt;code class=&quot;markdown-code&quot;&gt;bind&lt;/code&gt; assigns a file descriptor to a network address. &lt;code class=&quot;markdown-code&quot;&gt;close&lt;/code&gt; deallocates a file descriptor.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;How can we see &lt;em&gt;when&lt;/em&gt; our program is making system calls like &lt;code class=&quot;markdown-code&quot;&gt;bind&lt;/code&gt; and &lt;code class=&quot;markdown-code&quot;&gt;close&lt;/code&gt; ?&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;dtruss&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;dtruss is a tool that ships with Mac OS X. It was written by Brendan Gregg. It is similar to strace on linux systems. You can use it to see which system calls a program is making to the kernel. This means we can see if a program is attempting to close a socket when we expect it to, or if in fact the Go standard library is lying to us. After running dtruss you will see something like this:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dtruss -a -t &lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt; go &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; -run TestReconnect&lt;br&gt;PID/THRD         RELATIVE  ELAPSD    CPU SYSCALL&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;               &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;82830&lt;/span&gt;/0x978a1c:   &lt;span class=&quot;token number&quot;&gt;1357371&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;99&lt;/span&gt;     &lt;span class=&quot;token number&quot;&gt;95&lt;/span&gt; close&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0x5&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;82830&lt;/span&gt;/0x978a20:   &lt;span class=&quot;token number&quot;&gt;1378137&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;     &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; socket&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0x2, 0x2, 0x0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;       &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;82830&lt;/span&gt;/0x978a20:   &lt;span class=&quot;token number&quot;&gt;1378139&lt;/span&gt;       &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; fcntl&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0x5, 0x2, 0x1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;        &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;82830&lt;/span&gt;/0x978a20:   &lt;span class=&quot;token number&quot;&gt;1378142&lt;/span&gt;       &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; fcntl&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0x5, 0x3, 0x0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;        &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;82830&lt;/span&gt;/0x978a20:   &lt;span class=&quot;token number&quot;&gt;1378144&lt;/span&gt;       &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; fcntl&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0x5, 0x4, 0x6&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;        &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;82830&lt;/span&gt;/0x978a20:   &lt;span class=&quot;token number&quot;&gt;1378148&lt;/span&gt;       &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; setsockopt&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0x5, 0xFFFF, 0x20&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;       &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;82830&lt;/span&gt;/0x978a20:   &lt;span class=&quot;token number&quot;&gt;1378161&lt;/span&gt;       &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;      &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; bind&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0x5, 0xC821AA576C, 0x10&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;       &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; -1 Err&lt;span class=&quot;token comment&quot;&gt;#48&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;So here we can see a bunch of interesting information.&lt;/p&gt;
&lt;ul class=&quot;markdown-ul&quot;&gt;
&lt;li class=&quot;markdown-li&quot;&gt;Which threads are making which syscalls&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;How long they are taking&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;The arguments they&#39;re called with&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;The return value&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;One interesting thing here is that on the last line at the very end we see &lt;code class=&quot;markdown-code&quot;&gt;Err#48&lt;/code&gt;. This is our &amp;quot;bind: address already in use&amp;quot; error. In this particular trace we can see on the first line it looks like we close the &lt;code class=&quot;markdown-code&quot;&gt;0x5&lt;/code&gt; socket with no errors, and in the last line it says &lt;code class=&quot;markdown-code&quot;&gt;0x5&lt;/code&gt; is already in use when we try to &lt;code class=&quot;markdown-code&quot;&gt;bind&lt;/code&gt; it. Confusingly the &lt;code class=&quot;markdown-code&quot;&gt;0x5&lt;/code&gt; just refers to the file descriptor, and not the actual network address. The network address is stored in the second argument &lt;code class=&quot;markdown-code&quot;&gt;0xC821AA576C&lt;/code&gt; above. This is a pointer to the &lt;code class=&quot;markdown-code&quot;&gt;sockaddr&lt;/code&gt; struct passed to the kernel, which when dereferenced would look something like this:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;sockaddr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;   sa_family_t sa_family&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;   &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;        sa_data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 14 bytes of protocol address&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The part we&#39;re interested in is the &lt;code class=&quot;markdown-code&quot;&gt;sa_data&lt;/code&gt; field.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;So we need to dereference the pointer somehow. How is this possible ? Enter DTrace!&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;DTrace&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Dtrace is a powerful debugging tool originally built by Sun Microsystems for Solaris. It is also available on Mac OS X. The amazing thing about Dtrace is that it ships with its own scripting language called D. With these scripts you can write tracing programs which will execute upon entry/return of specified system calls. So using this we can actually write some tracing around &lt;code class=&quot;markdown-code&quot;&gt;bind&lt;/code&gt; to dereference the &lt;code class=&quot;markdown-code&quot;&gt;sockaddr&lt;/code&gt; struct, and ultimately find out which port is being bound.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;dtrace -c &lt;span class=&quot;token string&quot;&gt;&quot;go test -run TestReconnect&quot;&lt;/span&gt; -n &lt;span class=&quot;token string&quot;&gt;&#39;bind:entry { trace(arg0); trace(copyinstr(arg1)); }&#39;&lt;/span&gt; -f &lt;span class=&quot;token builtin class-name&quot;&gt;bind&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;This command is saying, &amp;quot;Execute my Go program, but whenever you see a &lt;code class=&quot;markdown-code&quot;&gt;bind&lt;/code&gt; system call invocation, run this D script.&amp;quot; In the script itself I&#39;m tracing the first two arguments. With the second argument I am tracing the result of a function called &lt;code class=&quot;markdown-code&quot;&gt;copyinstr&lt;/code&gt;. In D, the &lt;code class=&quot;markdown-code&quot;&gt;copyinstr&lt;/code&gt; function will dereference a pointer in user space and output the result as a string.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Running DTrace with these arguments gives me something like this:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;    &lt;span class=&quot;token number&quot;&gt;358&lt;/span&gt;                       bind:entry                 &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;br&gt;             &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;  &lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;  a  b  c  d  e  f  0123456789abcdef&lt;br&gt;         &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;: &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; 02 0b b9 7f 00 00 00 00 00 00 00 00 00 00 00  &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;At the end of the first line we see the &lt;code class=&quot;markdown-code&quot;&gt;5&lt;/code&gt; file descriptor being used like before. On the next lines we see the output of &lt;code class=&quot;markdown-code&quot;&gt;copyinstr(arg1)&lt;/code&gt;. This is the dereferenced pointer to the &lt;code class=&quot;markdown-code&quot;&gt;sockaddr&lt;/code&gt; struct. It looks like mostly unused memory. If we look at 3rd and 4th bytes in the above output we see the port number of the socket which is &lt;code class=&quot;markdown-code&quot;&gt;0x0bb9&lt;/code&gt; (3001). Now I can see that file descriptor &lt;code class=&quot;markdown-code&quot;&gt;0x5&lt;/code&gt; is binding to port 3001. Whew! 😅 Using this tool I was able to see that in fact an existing file descriptor &lt;em&gt;was&lt;/em&gt; still bound to the same port when the subsequent &lt;code class=&quot;markdown-code&quot;&gt;bind&lt;/code&gt; call was made.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;After digging through the Go standard library I eventually found my answer. Go documentation does mention that any blocked &lt;code class=&quot;markdown-code&quot;&gt;ReadFrom&lt;/code&gt; or &lt;code class=&quot;markdown-code&quot;&gt;WriteTo&lt;/code&gt; calls will be unblocked and return errors. What it fails to mention is that &lt;em&gt;until&lt;/em&gt; that happens, Go will not close the socket. Meaning that even after calling &lt;code class=&quot;markdown-code&quot;&gt;Close()&lt;/code&gt; on a &lt;code class=&quot;markdown-code&quot;&gt;net.PacketConn&lt;/code&gt; there is no guarantee that the socket has actually been closed. This is due to a &lt;a href=&quot;https://github.com/golang/go/blob/master/src/net/fd_mutex.go&quot;&gt;mutex&lt;/a&gt; around the underlying file descriptor in Go. The solution in my case was to use a semaphore in my code to ensure that all &lt;code class=&quot;markdown-code&quot;&gt;ReadFrom&lt;/code&gt; and &lt;code class=&quot;markdown-code&quot;&gt;WriteTo&lt;/code&gt; calls had returned before attempting to open a new socket on the same port.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The important thing about this exercise for me was being able to know for certain that I understood what my program was doing, and what my operating system was doing. This means I could be confident that the problem was sitting in between these layers in the stack.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Happy debugging! 😄&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>go test and parallelism</title>
    <link href="https://bryce.is/writing/code/go-test-and-parallelism.html"/>
    <updated>2023-02-13T09:30:00-00:00</updated>
    <id>https://bryce.is/writing/code/go-test-and-parallelism.html</id>
    <content type="html">&lt;p class=&quot;markdown-paragraph&quot;&gt;I was recently debugging an issue in some integration-style Go tests which made me realize that I didn&#39;t have a very deep
understanding of how parallelism works when using &lt;code class=&quot;markdown-code&quot;&gt;go test&lt;/code&gt;. I knew that there were ways that Go could parallelize tests, and I
thought it had something to do with using &lt;code class=&quot;markdown-code&quot;&gt;t.Parallel()&lt;/code&gt; inline in each of my test functions.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Because I feel the concurrency behavior of &lt;code class=&quot;markdown-code&quot;&gt;go test&lt;/code&gt; is non-obvious, and for posterity so I don&#39;t forget in the future,
I wanted to write something up here to document my understanding of how &lt;code class=&quot;markdown-code&quot;&gt;go test&lt;/code&gt; parallelization works as of
Go 1.19.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Testing a single package&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Let&#39;s start simple and assume we&#39;re testing a single package. Let&#39;s assume this package has no dependencies. By default,
unit tests in your package will run sequentially. In the below example, &lt;code class=&quot;markdown-code&quot;&gt;TestFirstTest&lt;/code&gt; will run first, followed by &lt;code class=&quot;markdown-code&quot;&gt;TestSecondTest&lt;/code&gt;. We&#39;ll run these using &lt;code class=&quot;markdown-code&quot;&gt;go test -v&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; main&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;testing&quot;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TestFirstTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;testing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Second&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;  fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TestSecondTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;testing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUN   TestFirstTest&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;br&gt;--- PASS: TestFirstTest &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.00s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUN   TestSecondTest&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;br&gt;--- PASS: TestSecondTest &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.00s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;PASS&lt;br&gt;ok  	test-concurrency	&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.180s&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Simple enough. We first see the output of &lt;code class=&quot;markdown-code&quot;&gt;1&lt;/code&gt;, followed by the output of &lt;code class=&quot;markdown-code&quot;&gt;2&lt;/code&gt;.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;You can also add &lt;code class=&quot;markdown-code&quot;&gt;t.Parallel()&lt;/code&gt; to your tests to make them run in parallel. First &lt;code class=&quot;markdown-code&quot;&gt;go test&lt;/code&gt; will run all tests sequentially, and each
time it encounters a call to &lt;code class=&quot;markdown-code&quot;&gt;t.Parallel()&lt;/code&gt;, it will &lt;code class=&quot;markdown-code&quot;&gt;PAUSE&lt;/code&gt; execution of the test (noted in the test output). Once all
sequential tests have completed, it will resume execution (&lt;code class=&quot;markdown-code&quot;&gt;CONT&lt;/code&gt;) of all tests which invoked &lt;code class=&quot;markdown-code&quot;&gt;t.Parallel()&lt;/code&gt;, in parallel.&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; main&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;testing&quot;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TestFirstTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;testing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1 start&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;	t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Parallel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;	time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Second&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;	fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1 end&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TestSecondTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;testing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Parallel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;	fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TestThirdTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;testing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUN   TestFirstTest&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; start&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; PAUSE TestFirstTest&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUN   TestSecondTest&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; PAUSE TestSecondTest&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUN   TestThirdTest&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;br&gt;--- PASS: TestThirdTest &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.00s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; CONT  TestFirstTest&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; CONT  TestSecondTest&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;br&gt;--- PASS: TestSecondTest &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.00s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; end&lt;br&gt;--- PASS: TestFirstTest &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.00s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;PASS&lt;br&gt;ok  	test-concurrency	&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.160s&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Here we first see the output of the sequential tests, including &lt;code class=&quot;markdown-code&quot;&gt;1 start&lt;/code&gt; from &lt;code class=&quot;markdown-code&quot;&gt;TestFirstTest&lt;/code&gt; before it invokes &lt;code class=&quot;markdown-code&quot;&gt;t.Parallel()&lt;/code&gt;. After &lt;code class=&quot;markdown-code&quot;&gt;TestFirstTest&lt;/code&gt; and &lt;code class=&quot;markdown-code&quot;&gt;TestThirdTest&lt;/code&gt; have run in sequence, &lt;code class=&quot;markdown-code&quot;&gt;TestSecondTest&lt;/code&gt; (&lt;code class=&quot;markdown-code&quot;&gt;2&lt;/code&gt;) and the remainder of &lt;code class=&quot;markdown-code&quot;&gt;TestFirstTest&lt;/code&gt; (&lt;code class=&quot;markdown-code&quot;&gt;1 end&lt;/code&gt;) are executed in parallel. Neat.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Testing Multiple Packages&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The above is simple enough for tests in a single package, but most codebases consist of more than a single package.
Let&#39;s define a hypothetical project with two packages: &lt;code class=&quot;markdown-code&quot;&gt;a&lt;/code&gt; and &lt;code class=&quot;markdown-code&quot;&gt;b&lt;/code&gt;. Let&#39;s define a test in each of them and run &lt;code class=&quot;markdown-code&quot;&gt;go test ./... -v&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; a&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;testing&quot;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TestA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;testing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Second&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;  fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; b&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;testing&quot;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TestB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;testing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUN   TestA&lt;br&gt;a&lt;br&gt;--- PASS: TestA &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.00s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;PASS&lt;br&gt;ok  	test-concurrency/a	&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.256s&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUN   TestB&lt;br&gt;b&lt;br&gt;--- PASS: TestB &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.00s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;PASS&lt;br&gt;ok  	test-concurrency/b	&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.068s&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Based on the output, it &lt;em&gt;looks&lt;/em&gt; like these tests ran sequentially. We see the output &lt;code class=&quot;markdown-code&quot;&gt;a&lt;/code&gt; before the output &lt;code class=&quot;markdown-code&quot;&gt;b&lt;/code&gt; despite
the fact that &lt;code class=&quot;markdown-code&quot;&gt;TestA&lt;/code&gt; utilizes &lt;code class=&quot;markdown-code&quot;&gt;time.Sleep&lt;/code&gt; before printing its output.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;But in fact, these tests
are being run in parallel. Confusingly, the output is buffered when running &lt;code class=&quot;markdown-code&quot;&gt;go test&lt;/code&gt; across multiple packages. The logs are batched until each test is completed. We can see this more clearly if we print some timestamp instead. i.e. &lt;code class=&quot;markdown-code&quot;&gt;fmt.Println(&amp;quot;a&amp;quot;, time.Now().Second())&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUN   TestA&lt;br&gt;a &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;br&gt;--- PASS: TestA &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.00s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;PASS&lt;br&gt;ok  	test-concurrency/a	&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.369s&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUN   TestB&lt;br&gt;b &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;br&gt;--- PASS: TestB &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.00s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;PASS&lt;br&gt;ok  	test-concurrency/b	&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.441s&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Printing the current second makes it clear that &lt;code class=&quot;markdown-code&quot;&gt;TestB&lt;/code&gt; logs a timestamp one second before &lt;code class=&quot;markdown-code&quot;&gt;TestA&lt;/code&gt;. This is because these tests are actually
being run in parallel. (As an aside there is an open issue &lt;a href=&quot;https://github.com/golang/go/issues/46959&quot;&gt;here&lt;/a&gt; in &lt;code class=&quot;markdown-code&quot;&gt;golang/go&lt;/code&gt; to address the buffered nature of &lt;code class=&quot;markdown-code&quot;&gt;go test&lt;/code&gt; across multiple packages).&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;These tests are not using &lt;code class=&quot;markdown-code&quot;&gt;t.Parallel()&lt;/code&gt;, so why are they being run in parallel? Well, by default Go runs tests in multiple packages in parallel. The &lt;code class=&quot;markdown-code&quot;&gt;t.Parallel()&lt;/code&gt; function we mentioned above only indicates whether tests &lt;em&gt;within the same package&lt;/em&gt; are run in parallel. To be more specific, &lt;code class=&quot;markdown-code&quot;&gt;go test&lt;/code&gt; accepts a flag called &lt;code class=&quot;markdown-code&quot;&gt;-p&lt;/code&gt;, or &lt;code class=&quot;markdown-code&quot;&gt;-parallel&lt;/code&gt; which is documented in
&lt;code class=&quot;markdown-code&quot;&gt;go help testflags&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;	-parallel n&lt;br&gt;	    Allow parallel execution of &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; functions that call t.Parallel, and&lt;br&gt;	    fuzz targets that call t.Parallel when running the seed corpus.&lt;br&gt;	    The value of this flag is the maximum number of tests to run&lt;br&gt;	    simultaneously.&lt;br&gt;	    While fuzzing, the value of this flag is the maximum number of&lt;br&gt;	    subprocesses that may call the fuzz &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; simultaneously, regardless of&lt;br&gt;	    whether T.Parallel is called.&lt;br&gt;	    By default, -parallel is &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; to the value of GOMAXPROCS.&lt;br&gt;	    Setting -parallel to values higher than GOMAXPROCS may cause degraded&lt;br&gt;	    performance due to CPU contention, especially when fuzzing.&lt;br&gt;	    Note that -parallel only applies within a single &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; binary.&lt;br&gt;	    The &lt;span class=&quot;token string&quot;&gt;&#39;go test&#39;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;command&lt;/span&gt; may run tests &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; different packages&lt;br&gt;	    &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; parallel as well, according to the setting of the -p flag&lt;br&gt;	    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;see &lt;span class=&quot;token string&quot;&gt;&#39;go help build&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;This &lt;code class=&quot;markdown-code&quot;&gt;-parallel&lt;/code&gt; flag allows us to control the parallelism of tests which use &lt;code class=&quot;markdown-code&quot;&gt;t.Parallel()&lt;/code&gt;, but critically it also specifies the
parallelism across multiple packages. The documentation says &amp;quot;By default, &lt;code class=&quot;markdown-code&quot;&gt;-parallel&lt;/code&gt; is set to the value of &lt;code class=&quot;markdown-code&quot;&gt;GOMAXPROCS&lt;/code&gt;.&amp;quot;; and &lt;code class=&quot;markdown-code&quot;&gt;GOMAXPROCS&lt;/code&gt; defaults to the number of CPU cores on the machine. According to the docs:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;GOMAXPROCS sets the maximum number of CPUs that can be executing simultaneously and returns the previous setting. It defaults to the value of runtime.NumCPU.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;So putting it all together, running &lt;code class=&quot;markdown-code&quot;&gt;go test ./...&lt;/code&gt; will use &lt;code class=&quot;markdown-code&quot;&gt;GOMAXPROCS&lt;/code&gt; as the default value of &lt;code class=&quot;markdown-code&quot;&gt;-parallel&lt;/code&gt;, &lt;code class=&quot;markdown-code&quot;&gt;GOMAXPROCS&lt;/code&gt; defaults to the number of cores on the machine, and therefore &lt;code class=&quot;markdown-code&quot;&gt;go test ./...&lt;/code&gt; will run all package tests in parallel across all cores on the machine.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Multiple Packages and package initialization&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I want to touch on one other non-obvious feature of &lt;code class=&quot;markdown-code&quot;&gt;go test&lt;/code&gt;, which is how imported packages are initialized in tests. In order
to demonstrate this, we need to add a third package into the mix which we&#39;ll call &lt;code class=&quot;markdown-code&quot;&gt;c&lt;/code&gt;. Let&#39;s suppose that both &lt;code class=&quot;markdown-code&quot;&gt;a&lt;/code&gt; and &lt;code class=&quot;markdown-code&quot;&gt;b&lt;/code&gt;
are importing the package &lt;code class=&quot;markdown-code&quot;&gt;c&lt;/code&gt; as part of their import chain. We&#39;ll modify our &lt;code class=&quot;markdown-code&quot;&gt;TestA&lt;/code&gt; and &lt;code class=&quot;markdown-code&quot;&gt;TestB&lt;/code&gt; functions to print a
global value exported from &lt;code class=&quot;markdown-code&quot;&gt;c&lt;/code&gt;. Finally, we&#39;ll add an &lt;code class=&quot;markdown-code&quot;&gt;init()&lt;/code&gt; function to the &lt;code class=&quot;markdown-code&quot;&gt;c&lt;/code&gt; package. Remember that &lt;code class=&quot;markdown-code&quot;&gt;init&lt;/code&gt; is a special package-level function that is called once after the imported packages have been initialized.&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; a&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;test-concurrency/c&quot;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;testing&quot;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TestA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;testing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Global&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; b&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;test-concurrency/c&quot;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token string&quot;&gt;&quot;testing&quot;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TestB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;testing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	fmt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Global&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; c&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; Global &lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	Global &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Nanosecond&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUN   TestA&lt;br&gt;a &lt;span class=&quot;token number&quot;&gt;455538000&lt;/span&gt;&lt;br&gt;--- PASS: TestA &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.00s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;PASS&lt;br&gt;ok  	test-concurrency/a	&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cached&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; RUN   TestB&lt;br&gt;b &lt;span class=&quot;token number&quot;&gt;381870000&lt;/span&gt;&lt;br&gt;--- PASS: TestB &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.00s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;PASS&lt;br&gt;ok  	test-concurrency/b	&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cached&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;?   	test-concurrency/c	&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;no &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; files&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;You might expect that the output above would be &lt;code class=&quot;markdown-code&quot;&gt;b 455538000&lt;/code&gt; instead of &lt;code class=&quot;markdown-code&quot;&gt;b 381870000&lt;/code&gt; given that the &lt;code class=&quot;markdown-code&quot;&gt;init&lt;/code&gt; function
should only run once, however (and this is the non-obvious part), both &lt;code class=&quot;markdown-code&quot;&gt;a&lt;/code&gt; and &lt;code class=&quot;markdown-code&quot;&gt;b&lt;/code&gt; actually import and initialize a separate instance of the &lt;code class=&quot;markdown-code&quot;&gt;c&lt;/code&gt; package. 🤔&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The reason for this is that, under the hood, &lt;code class=&quot;markdown-code&quot;&gt;go test&lt;/code&gt; is actually compiling and running separate binaries for each of your packages&#39; tests. These binaries include the test code, the code being tested, and any dependencies. In fact, if you run &lt;code class=&quot;markdown-code&quot;&gt;go test ./... -work&lt;/code&gt;, you can access the temporary directory used for this process. Within this directory, you will find an executable for each of your packages.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;This helps explain why references exported from &lt;code class=&quot;markdown-code&quot;&gt;c&lt;/code&gt; are not shared between the &lt;code class=&quot;markdown-code&quot;&gt;a&lt;/code&gt; and &lt;code class=&quot;markdown-code&quot;&gt;b&lt;/code&gt; package tests, and the &lt;code class=&quot;markdown-code&quot;&gt;init&lt;/code&gt; function of &lt;code class=&quot;markdown-code&quot;&gt;c&lt;/code&gt; is invoked twice. In the case of simple unit testing, this is generally not problematic, but can lead to unexpected behavior if the tests are integration-style tests which rely on package-level locks to manage system-level resources like files, ports, etc.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Understanding these nuances around Go testing will help you write better and faster test suites. Now, go forth and improve your coverage. 🫡&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>fully nix-pilled</title>
    <link href="https://bryce.is/writing/code/fully-nix-pilled.html"/>
    <updated>2024-06-21T05:00:00-00:00</updated>
    <id>https://bryce.is/writing/code/fully-nix-pilled.html</id>
    <content type="html">&lt;p class=&quot;markdown-paragraph&quot;&gt;I recently bought a new MacBook, and instead of manually installing everything for the &lt;code class=&quot;markdown-code&quot;&gt;n&lt;/code&gt;th time, I decided to go down the path of using Nix and nix-darwin to codify my dev machine configuration. If you&#39;re curious, let&#39;s dive in.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;What is Nix?&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Nix is a few things which I would break down into three categories:&lt;/p&gt;
&lt;ol class=&quot;markdown-ol&quot;&gt;
&lt;li class=&quot;markdown-li&quot;&gt;A configuration and build system referred to as &amp;quot;Nix&amp;quot;.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;A configuration &lt;em&gt;language&lt;/em&gt;, confusingly also referred to as &amp;quot;Nix&amp;quot;.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;A package manager wherein the official packages are referred to as &amp;quot;nixpkgs&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;First and foremost, Nix is a configuration system for describing declaratively how your system should be configured. This includes things like packages, applications, and shell configuration, but can even include OS settings like your preferred scroll direction (natural scrolling disabled of course, for the sophisticated among us). If you&#39;ve ever used something like Terraform or CloudFormation to set up your infrastructure, then in this context you might think of Nix as being like Terraform for your personal machine. When you &amp;quot;build&amp;quot; a version of your system configuration, Nix produces a &amp;quot;generation&amp;quot;, which conceptually can be thought of as a deterministic snapshot of your system given the current configuration.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Second, the name &amp;quot;Nix&amp;quot; is also used (confusingly) to refer to the underlying configuration language itself that the configuration files are written in. This language is a declarative scripting language which is used to configure your system. In my experience it was relatively easy to get started with. The documentation is great, and there are a number of existing examples to work from.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Finally, Nix is a package manager. It has an official repository of packages called &amp;quot;nixpkgs&amp;quot; which you can browse &lt;a href=&quot;https://search.nixos.org/packages&quot;&gt;here&lt;/a&gt;. When you define your configuration, you&#39;ll likely specify packages which will be sourced from nixpkgs. For example, things like &lt;code class=&quot;markdown-code&quot;&gt;git&lt;/code&gt;, or &lt;code class=&quot;markdown-code&quot;&gt;zsh&lt;/code&gt;, or &lt;code class=&quot;markdown-code&quot;&gt;python&lt;/code&gt;.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;What is nix-darwin?&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;As my personal computer is running macOS, I am also using &lt;a href=&quot;https://github.com/LnL7/nix-darwin&quot;&gt;nix-darwin&lt;/a&gt;, which is a set of modules specifically for configuring macOS. It allows you (among other things) to modify operating system settings like the dock, hot corners, dark mode, etc. Not every single item within &amp;quot;System Settings&amp;quot; is supported yet, but it gets you most of the way there.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Ok, so that&#39;s a high-level overview of Nix, but why bother with any of that? For myself, I&#39;d break it down as follows:&lt;/p&gt;
&lt;h3 class=&quot;markdown-h3&quot;&gt;Pros&lt;/h3&gt;
&lt;ul class=&quot;markdown-ul&quot;&gt;
&lt;li class=&quot;markdown-li&quot;&gt;Improved auditability. I can more easily see at a glance what is installed on my system. No more forgetting about some random package I installed 6 months ago and never use anymore!&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;If something goes wrong, rollbacks with nix are super easy. If I break something critical, I can always roll back to a previous version of my system.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;Peace of mind that I could blow away my entire machine and start over quickly if needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 class=&quot;markdown-h3&quot;&gt;Cons&lt;/h3&gt;
&lt;ul class=&quot;markdown-ul&quot;&gt;
&lt;li class=&quot;markdown-li&quot;&gt;There was some initial investment required to get my system set up in the way I like. But I only needed to do this once!&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;There was some learning curve in ramping up on Nix the language.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;GUI apps on macOS are not well supported, so you still need to use homebrew for these. You can at least configure which homebrew casks should be installed on the system via nix-darwin.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;Ideally, every single macOS system setting would be configurable with nix-darwin, but that&#39;s not true (yet).&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Using Nix for my dev machine has been working great for me so far, and I&#39;m now fully nix-pilled. You can check out my configuration &lt;a href=&quot;https://github.com/prettymuchbryce/dotfiles&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;We could go deeper down the rabbit hole and talk in more detail about how Nix works under the hood. Or we could speak to more of the Nix ecosystem like home-manager, flakes, or NixOS; but I&#39;ll stop here for now. 🙃&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>autotidy</title>
    <link href="https://bryce.is/writing/code/autotidy.html"/>
    <updated>2026-02-04T09:00:00-00:00</updated>
    <id>https://bryce.is/writing/code/autotidy.html</id>
    <content type="html">&lt;p class=&quot;markdown-paragraph&quot;&gt;I recently released a new open source project called &lt;a href=&quot;https://github.com/prettymuchbryce/autotidy&quot;&gt;autotidy&lt;/a&gt;. It&#39;s a file-system organizer ala &lt;a href=&quot;https://www.noodlesoft.com/&quot;&gt;Hazel&lt;/a&gt;, &lt;a href=&quot;https://github.com/maid/maid&quot;&gt;Maid&lt;/a&gt;, and &lt;a href=&quot;https://github.com/tfeldmann/organize&quot;&gt;Organize&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;What does it do exactly? Well, it allows you to define rules that should be applied when a directory changes. For example, I use it to organize my Downloads folder. When I download a file I often want it to automatically end up in a certain place. For example, audio files that begin with the name &amp;quot;New Recording&amp;quot; are voice memos. Images that begin with &amp;quot;ChatGPT&amp;quot; or &amp;quot;Gemini_&amp;quot; are images generated with AI models.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;With autotidy I can sort these files into better homes by defining rules like this:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Sort AI images&lt;br&gt;    &lt;span class=&quot;token key atrule&quot;&gt;locations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ~/Downloads&lt;br&gt;    &lt;span class=&quot;token key atrule&quot;&gt;filters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Gemini_*&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ChatGPT*&lt;br&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;extension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;png&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; jpeg&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token key atrule&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ~/images/slop&lt;/code&gt;&lt;/pre&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Why build it?&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I built autotidy to solve this problem for myself after finding that none of the alternatives met my goals. I needed something that met the following requirements:&lt;/p&gt;
&lt;ul class=&quot;markdown-ul&quot;&gt;
&lt;li class=&quot;markdown-li&quot;&gt;Works cross-platform (Linux &amp;amp; MacOS specifically)&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;Free &amp;amp; Open Source&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;Declarative and configuration-based. No coding required.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;Installable and configurable via Nix (how I manage my systems)&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;Automatic. i.e. Doesn&#39;t require me to manually run a one-off command to invoke my rules.&lt;/li&gt;
&lt;li class=&quot;markdown-li&quot;&gt;(Optional) No runtime dependencies (i.e. No Ruby, Node, Python etc)&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;To my surprise, the alternatives I found all had their own shortcomings.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;strong&gt;Hazel&lt;/strong&gt;: MacOS only, proprietary/commerical.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;strong&gt;Maid&lt;/strong&gt;: Requires Ruby runtime. Requires writing Ruby to define rules.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;strong&gt;Organize&lt;/strong&gt;: Requires Python runtime. No built-in file watching. Requires rules to be manually run (or via &lt;code class=&quot;markdown-code&quot;&gt;cron&lt;/code&gt;, etc).&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;This is not a critique of these tools or their developers, just that my requirements differed. They are all fantastic in their own ways, and I borrowed ideas from each of them.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Technical details&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I wrote autotidy in Go. I debated writing it in Rust, but I am less familiar with Rust and I wanted to knock something out relatively quickly. There is nothing overly complex about how autotidy works. It reads a configuration file, builds rules in memory, watches files for changes, and then applies the rules to the appropriate files. But there were some things that I stumbled across when making it that I thought might be interesting to mention.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Watching for changes with fsnotify&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Watching directories for changes is a bit of a tedious problem, especially if you want to do so in a way that is cross-platform. On Linux this is done with &lt;code class=&quot;markdown-code&quot;&gt;inotify&lt;/code&gt;, on macOS &lt;code class=&quot;markdown-code&quot;&gt;kqueue&lt;/code&gt;, and on Windows &lt;code class=&quot;markdown-code&quot;&gt;ReadDirectoryChangesW&lt;/code&gt;. Instead of re-implementing the wheel here I decided to use &lt;a href=&quot;https://github.com/fsnotify/fsnotify&quot;&gt;fsnotify&lt;/a&gt; which provides a standard interface around all of these implementations. There are still some cross-platform details that differ, but they are relatively few and manageable.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I also stumbled across some interesting issues along the way. Like for example, what happens if a directory that is being watched is deleted? or what happens if the user defines a rule for a directory which doesn&#39;t exist until later? To solve this problem I defined what I call &amp;quot;Missing Roots&amp;quot;, locations that don&#39;t exist now, but may exist in the future. When a location that is defined in the config doesn&#39;t exist, I recursively move up the file tree until I find a directory that does exist, and I watch this directory for changes that result in getting closing to the target directory. This works well, but it comes with some other problems. Like for example, what happens if the Missing Root is located at &lt;code class=&quot;markdown-code&quot;&gt;/a&lt;/code&gt;, and the user in quick-succession creates &lt;code class=&quot;markdown-code&quot;&gt;/a/b/c/d/location&lt;/code&gt;? Our watch of &lt;code class=&quot;markdown-code&quot;&gt;/a&lt;/code&gt; may notice the creation of &lt;code class=&quot;markdown-code&quot;&gt;/a/b&lt;/code&gt;, but by the time it begins watching this directory &lt;code class=&quot;markdown-code&quot;&gt;/a/b/c&lt;/code&gt; may have already been created. This necessitates a bit of logic to ensure that created directories are not missed. Further, because file changes can be erratic, and we want to maintain performance, we need to debounce our operations by some small period with each change.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;&lt;code class=&quot;markdown-code&quot;&gt;fsnotify&lt;/code&gt; does not tell us &lt;em&gt;what&lt;/em&gt; new files created are. To determine whether the file is a directory (to look for the Missing Root, or to recurse if the rule is a recursive rule) we need to ask the Operating System what type of file it is. In order to maintain performance I ended up using &lt;code class=&quot;markdown-code&quot;&gt;readdir&lt;/code&gt; if the number of changed files is greater than some threshold, rather than &lt;code class=&quot;markdown-code&quot;&gt;stat&lt;/code&gt;ing every file, which could be slower if there are dozens or hundreds of file changes at once.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;afero for file-system abstraction&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I used &lt;a href=&quot;https://github.com/spf13/afero&quot;&gt;afero&lt;/a&gt; as a way to abstract file system operations. This was useful in unit tests where I wanted to operate on files in memory rather than on the file-system itself. It had the additional benefit of allowing me to build &amp;quot;dry-run&amp;quot; functionality, which is the default when running one-off rules via &lt;code class=&quot;markdown-code&quot;&gt;autotidy run&lt;/code&gt;. Using afero meant I could simulate the result of running rules by running them in memory by using a Copy-On-Write implementation, and then print information about the resulting changes to the terminal without actual making them.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Packaging and distribution&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;One of the biggest challenges with building a cross-platform headless program like this is how to distribute it. This is arguably one advantage of using a runtime like Python, Ruby, or Node. Users can simply use &lt;code class=&quot;markdown-code&quot;&gt;pip&lt;/code&gt; or &lt;code class=&quot;markdown-code&quot;&gt;npm&lt;/code&gt; to install the software. While I could have used &lt;code class=&quot;markdown-code&quot;&gt;go install&lt;/code&gt; for the CLI, it wouldn&#39;t be sufficient for a daemon which needs to run in the background and launch at system startup. On linux this means adding a unit to &lt;code class=&quot;markdown-code&quot;&gt;systemd&lt;/code&gt;, on MacOS &lt;code class=&quot;markdown-code&quot;&gt;launchd&lt;/code&gt;, and on Windows the registry.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I explored a few different approaches here for varying platforms.&lt;/p&gt;
&lt;h3 class=&quot;markdown-h3&quot;&gt;Homebrew&lt;/h3&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Homebrew was most simple, and is done by just creating a &lt;a href=&quot;https://github.com/prettymuchbryce/homebrew-tap&quot;&gt;tap repository&lt;/a&gt; and instructing the user to &lt;code class=&quot;markdown-code&quot;&gt;brew install&lt;/code&gt; from this repository.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; prettymuchbryce/tap/autotidy&lt;br&gt;brew services start autotidy&lt;br&gt;autotidy status&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;The &lt;code class=&quot;markdown-code&quot;&gt;brew services start&lt;/code&gt; line is required for persistent background processes.&lt;/p&gt;
&lt;h3 class=&quot;markdown-h3&quot;&gt;Nix&lt;/h3&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Nix was also relatively simple. You simply add a &lt;code class=&quot;markdown-code&quot;&gt;flake.nix&lt;/code&gt; file to the repository and instruct the user to add it as an input to their configuration. This was important to me as it&#39;s the one I personally use.&lt;/p&gt;
&lt;h3 class=&quot;markdown-h3&quot;&gt;Other Linux&lt;/h3&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I was unsure how to tackle other linux distributions aside from Nix. For new projects, pursuing official inclusion in big package managers like &lt;code class=&quot;markdown-code&quot;&gt;yum&lt;/code&gt; or &lt;code class=&quot;markdown-code&quot;&gt;apt&lt;/code&gt; seems inappropriate. I ended up crafting a one-liner to run an &lt;a href=&quot;https://github.com/prettymuchbryce/autotidy/blob/master/install/linux/install.sh&quot;&gt;install script&lt;/a&gt;, as well as creating deb/rpm packages with &lt;a href=&quot;https://nfpm.goreleaser.com/&quot;&gt;nfpm&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I&#39;m not crazy about curl piping scripts into a shell for many reasons, so I am not totally happy with this solution.&lt;/p&gt;
&lt;h3 class=&quot;markdown-h3&quot;&gt;Windows&lt;/h3&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Windows is similar to the above. There is a &lt;a href=&quot;https://github.com/prettymuchbryce/autotidy/blob/master/install/windows/install.ps1&quot;&gt;powershell script&lt;/a&gt; that installs and sets up the service.&lt;/p&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;I have the least confidence in this platform, and while I have done cursory manual and automated testing, I don&#39;t use Windows regularly enough to be sure that I have adhered to all of the standard idioms.&lt;/p&gt;
&lt;h3 class=&quot;markdown-h3&quot;&gt;Testing&lt;/h3&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;In addition to manual testing, I setup installation-related &lt;a href=&quot;https://github.com/prettymuchbryce/autotidy/blob/master/.github/workflows/install-tests.yml&quot;&gt;integration tests&lt;/a&gt; for each platform. At the very least this helps me catch any issues related to install before shipping new versions.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Working with Claude&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;Since it&#39;s 2026, and therefore I am compelled to mention AI in this post, I should say that I made heavy use of Claude Code while building this project. It is not &amp;quot;vibe-coded&amp;quot; in the sense that I threw prompts at the wall and hoped for the best. I found myself using Claude Code to help answer questions, perform menial tasks (like moving files around, or setting up boilerplate), as well as writing additional unit test cases. Against common ai-influencer wisdom, I strived to review every line of code and in doing so found a healthy amount of mistakes and bugs that were missed by the agent. I am still trying to find the right balance here of using agents to move faster, while also retaining my own strong opinions about architecture and maintainability.&lt;/p&gt;
&lt;h2 class=&quot;markdown-h2&quot;&gt;Summary&lt;/h2&gt;
&lt;p class=&quot;markdown-paragraph&quot;&gt;This was a nice little side project to build, and I had fun with it. I am not sure if the core problem is a common one, or if my solution is differentiated enough to lure users away from the existing solutions. Ultimately I saw this as an opportunity to solve my own problem. I&#39;d like to get in the habit of doing more things like this in the future. Thanks for reading!&lt;/p&gt;
</content>
  </entry>
</feed> 
