<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>chrs.dev</title>
    <link>https://chrs.dev/</link>
    <description>Recent content on chrs.dev</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-US</language>
    <managingEditor>christian@chrs.dev (Christian Mutti)</managingEditor>
    <webMaster>christian@chrs.dev (Christian Mutti)</webMaster>
    <copyright>Christian Mutti (CC BY 4.0)</copyright>
    <lastBuildDate>Sun, 07 Apr 2024 22:45:00 -0300</lastBuildDate>
    <atom:link href="https://chrs.dev/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>&#34;Clean&#34; Code, Horrible Performance in Rust</title>
      <link>https://chrs.dev/blog/clean-code-rust/</link>
      <pubDate>Sun, 07 Apr 2024 22:45:00 -0300</pubDate><author>christian@chrs.dev (Christian Mutti)</author>
      <guid>https://chrs.dev/blog/clean-code-rust/</guid>
      <description>I was just recently going through some old episodes from Software Engineering Radio when I came across this one episode featuring Casey Muratori, where he goes through some of his thoughts around his video from February 2023, titled &amp;quot;&amp;lsquo;Clean&amp;rsquo; Code, Horrible Performance&amp;quot;. I was actually already aware of the video by this time, but listening through the episode gave me an itch to see these concepts in my reality, experiment them by myself.</description>
      <content:encoded><![CDATA[<p>I was just recently going through some old episodes from
<a href="https://se-radio.net/">Software Engineering Radio</a> when I came across
<a href="https://se-radio.net/2023/08/se-radio-577-casey-muratori-on-clean-code-horrible-performance/">this one episode</a>
featuring <a href="https://twitter.com/cmuratori">Casey Muratori</a>, where he goes through
some of his thoughts around his video from February 2023, titled
<a href="https://www.youtube.com/watch?v=tD5NrevFtbU">&quot;&lsquo;Clean&rsquo; Code, Horrible Performance&quot;</a>.
I was actually already aware of the video by this time, but listening through
the episode gave me an itch to see these concepts in my reality, experiment them
by myself.</p>
<p>I chose to rewrite the ideas Casey presented in the video in Rust, trying to be
idiomatic is not really the goal of the solutions you&rsquo;ll see below, but rather
experiment with how structuring the code may lead to a big performance penalty.</p>
<p>All the code I reference in this post is available in
<a href="https://gist.github.com/chrsmutti/698f979ad07be89ec3319dceb13565a9">this Gist</a>.</p>
<hr>
<p>You can also check this awesome video by
<a href="https://www.youtube.com/@lavafroth">@lavafroth</a>, that goes over this article
and further explains some areas I might have missed:
<a href="https://www.youtube.com/watch?v=GA4ONupSl8Y&feature=youtu.be">Two Decades of Hardware Optimizations Down The Drain</a></p>
<h2 id="base-case-traits">Base Case: Traits</h2>
<p>Starting with all the &ldquo;Clean&rdquo; Code principles, we would likely implement
something that looks like the code seen below:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">trait</span><span class="w"> </span><span class="n">Shape</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">area</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">f32</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Square</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="n">side</span>: <span class="kt">f32</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Shape</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Square</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">area</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">f32</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">side</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">side</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w"></span><span class="c1">// ... the same for Rectangle, Triangle and Circle
</span></span></span></code></pre></div><p>Running the accumulator test Casey shows in the video, yields us a runtime of
<code>54,956 ns/iter</code> for <code>10240</code> items (more detailed information on the
<a href="/blog/clean-code-rust/#annex-1-benchmark-results">annex down below</a>). We&rsquo;ll use this as our baseline
going forward.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="w">    </span><span class="cp">#[bench]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">total_area</span><span class="p">(</span><span class="n">b</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="n">Bencher</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">shapes</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span><span class="w"> </span><span class="n">Shape</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">init</span><span class="p">(</span><span class="no">COUNT</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">        </span><span class="n">b</span><span class="p">.</span><span class="n">iter</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">accum</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="k">f32</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">            </span><span class="k">for</span><span class="w"> </span><span class="n">shape</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">&amp;</span><span class="n">shapes</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">                </span><span class="n">accum</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">shape</span><span class="p">.</span><span class="n">area</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">            </span><span class="n">accum</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="p">}</span></span></span></code></pre></div><p>If you&rsquo;re more familiar with Rust you&rsquo;ll immediately catch the use of <code>Box</code>
there as a possible location for optimization. For our constraints, we do need
to box the values when constructing them as we need to have a &ldquo;polymorphic
list&rdquo;, and because we&rsquo;re using a trait as our abstraction for <code>Shape</code>, the
values of our shapes vec are of unknown size to the compiler.</p>
<p>Our first performance gain comes without touching much of the implementation
code, but rather, the code in the &ldquo;caller&rdquo; side (the benchmark function). Using
4 accumulators instead of one:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="w">    </span><span class="cp">#[bench]</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">total_area_sum4</span><span class="p">(</span><span class="n">b</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="n">Bencher</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">shapes</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span><span class="w"> </span><span class="n">Shape</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">init</span><span class="p">(</span><span class="no">COUNT</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">        </span><span class="n">b</span><span class="p">.</span><span class="n">iter</span><span class="p">(</span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">accum1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="k">f32</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">accum2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="k">f32</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">accum3</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="k">f32</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">accum4</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="k">f32</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="no">COUNT</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">4</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">iter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">            </span><span class="k">while</span><span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">iter</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">                </span><span class="n">accum1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">shapes</span><span class="p">[</span><span class="n">iter</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">4</span><span class="p">].</span><span class="n">area</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">                </span><span class="n">accum2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">shapes</span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">iter</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">4</span><span class="p">)].</span><span class="n">area</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">                </span><span class="n">accum3</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">shapes</span><span class="p">[</span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">iter</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">4</span><span class="p">)].</span><span class="n">area</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">                </span><span class="n">accum4</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">shapes</span><span class="p">[</span><span class="mi">3</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">iter</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">4</span><span class="p">)].</span><span class="n">area</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">                </span><span class="n">iter</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">            </span><span class="n">accum1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">accum2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">accum3</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">accum4</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="w">        </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">    </span><span class="p">}</span></span></span></code></pre></div><p>This improves on the baseline by <strong>3.1x</strong>, executing at a runtime of
<code>17,725 ns/iter</code>. <strong>Why?</strong> A better utilization of CPU cycles. Modern CPUs are
able to handle parallel computations such as the one done above, but the
compiler may not take advantage of this if they&rsquo;re not easily recognizable.</p>
<p>Of course, the code above is not really something we can easily copy paste and
use in other solutions because there are a lot of assumptions we need to hold,
the biggest one being: Is count divisible by 4? But that is besides the point,
as we&rsquo;re mostly <a href="https://en.wikipedia.org/wiki/Bit_twiddler">bit twiddling</a>
here.</p>
<h2 id="still-idiomatic-match">Still Idiomatic: Match</h2>
<p>Going forward, Casey then breaks the &ldquo;Polymorphism Rule&rdquo; of &ldquo;Clean&rdquo; Code, and
writes the same implementation using a switch statement. In idiomatic Rust, we
can equate that to a match on a enum.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">enum</span> <span class="nc">Shape</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">    </span><span class="n">Square</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">side</span>: <span class="kt">f32</span> <span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="n">Rectangle</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">width</span>: <span class="kt">f32</span><span class="p">,</span><span class="w"> </span><span class="n">height</span>: <span class="kt">f32</span> <span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">    </span><span class="n">Triangle</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">base</span>: <span class="kt">f32</span><span class="p">,</span><span class="w"> </span><span class="n">height</span>: <span class="kt">f32</span> <span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="n">Circle</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">radius</span>: <span class="kt">f32</span> <span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Shape</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">area</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">f32</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">        </span><span class="k">match</span><span class="w"> </span><span class="bp">self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">            </span><span class="n">Shape</span>::<span class="n">Square</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">side</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">side</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">side</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">            </span><span class="n">Shape</span>::<span class="n">Rectangle</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">width</span><span class="p">,</span><span class="w"> </span><span class="n">height</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">width</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">height</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">            </span><span class="n">Shape</span>::<span class="n">Triangle</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">base</span><span class="p">,</span><span class="w"> </span><span class="n">height</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="mf">0.5</span><span class="k">f32</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">base</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">height</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">            </span><span class="n">Shape</span>::<span class="n">Circle</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">radius</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="no">PI</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">radius</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">radius</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><p>The code here is still very readable, follows some very good conventions and is
something that you&rsquo;d see every day in Rust. There is a drawback of this
implementation if you&rsquo;re writing a library: the dependents of said library would
not be able to extend the <code>Shape</code> system and add a <code>Hexagon</code> for example.</p>
<p>With the code structured this way, we see a whopping <strong>3.2x</strong> improvement from
the baseline when using the regular <code>for</code> loop, and a massive <strong>8.5x</strong>
improvement when using the <code>_sum4</code> variant (<code>17,141 ns/iter</code> and
<code>6,434 ns/iter</code>).</p>
<p>This is the knowledge I&rsquo;ll take from this experiment the most, because this is
still very idiomatic code, and knowing this performance difference is beneficial
when tackling performance critical code. This is where I can see most value from
the
<a href="https://www.computerenhance.com/p/welcome-to-the-performance-aware">&ldquo;Performance-aware Programming&rdquo;</a>
that Casey advocates for.</p>
<p>My assumptions is that the performance gains here come mostly from the removal
of the <code>Box</code> construct. Having the shapes represented as enum variants instead
of trait implementors makes their size known at compile time and reduces the
need of the <code>Box</code> to represent a &ldquo;polymorphic list&rdquo; (using quotes here is very
applicable, because this is not really a &ldquo;polymorphic list&rdquo; on the original
sense of the word).</p>
<h2 id="breaking-with-idiomatic-rust-lookup-table">Breaking with Idiomatic Rust: Lookup Table</h2>
<p>Moving forward with the optimizations we then come across using a lookup table
for the multiplier constants. If you look closely at the <code>match</code> code above,
you&rsquo;ll notice a pattern. Casey mentions this pattern in his video and also
claims that moving the code out of the Polymorphic variant and into the
<code>if-else/switch</code> style (or in our case the <code>match</code> style) highlights this
pattern.</p>
<p>Trying to still maintain some semblance of idiomatic Rust, I went with a
different approach for the lookup table, using a constructor function for
<code>Shape</code>s and storing the multiplier within the <code>struct</code> itself. This leaves us
with:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">enum</span> <span class="nc">ShapeType</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">    </span><span class="n">Square</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">side</span>: <span class="kt">f32</span> <span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span><span class="n">Rectangle</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">width</span>: <span class="kt">f32</span><span class="p">,</span><span class="w"> </span><span class="n">height</span>: <span class="kt">f32</span> <span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">    </span><span class="n">Triangle</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">base</span>: <span class="kt">f32</span><span class="p">,</span><span class="w"> </span><span class="n">height</span>: <span class="kt">f32</span> <span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="n">Circle</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">radius</span>: <span class="kt">f32</span> <span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span><span class="k">struct</span> <span class="nc">Shape</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="n">multiplier</span>: <span class="kt">f32</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="n">width</span>: <span class="kt">f32</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">    </span><span class="n">height</span>: <span class="kt">f32</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w"></span><span class="k">impl</span><span class="w"> </span><span class="n">Shape</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">shape_type</span>: <span class="nc">ShapeType</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">        </span><span class="k">match</span><span class="w"> </span><span class="n">shape_type</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">            </span><span class="n">ShapeType</span>::<span class="n">Square</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">side</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">Shape</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">                </span><span class="n">multiplier</span>: <span class="mi">1</span><span class="k">f32</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w">                </span><span class="n">width</span>: <span class="nc">side</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w">                </span><span class="n">height</span>: <span class="nc">side</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">            </span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w">            </span><span class="c1">// ... the same for Rectangle, Triangle and Circle
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c1"></span><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">    </span><span class="k">fn</span> <span class="nf">area</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">f32</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">        </span><span class="bp">self</span><span class="p">.</span><span class="n">multiplier</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">width</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">height</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div><p>Styling the code this way allows us to create shapes like so:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="n">shape</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Shape</span>::<span class="n">new</span><span class="p">(</span><span class="n">Square</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">side</span>: <span class="mi">2</span><span class="k">f32</span><span class="w"> </span><span class="p">})</span><span class="w"> </span><span class="c1">// Shape::Square { side: 2f32 }
</span></span></span></code></pre></div><p>This is not so different from what we saw in the more idiomatic examples using
<code>trait</code>s and <code>match</code>.</p>
<p>This code is <strong>6.4x</strong> faster than the baseline using the simple benchmark and
<strong>11x</strong> faster using the <code>_sum4</code> variant. In this example, we can see that the
sizes are known at compile time and there&rsquo;s probably some other optimization of
the instruction sent to the CPU that I&rsquo;m not aware of.</p>
<h2 id="breaking-the-small-functions-principle-corner_area">Breaking the &ldquo;small functions&rdquo; principle: <code>corner_area</code></h2>
<p>To break the &ldquo;small functions that only do a single thing&rdquo; mantra from &ldquo;Clean&rdquo;
Code, Casey introduces a <code>CornerCont()</code> information to the Shape <code>struct</code>. The
resulting value should be <code>1 / (1 + shape.CornerCount() + shape.Area())</code>.</p>
<p>Implementation wise they are very similar from what we&rsquo;ve seen so far, and the
performance gains we seen before were also observed when calculating with the
<code>corner</code>.</p>
<p>The base case yielded a runtime of <code>54,302 ns/iter</code>. Changing the <code>trait</code>
implementation into a <code>match</code> statement, we see the performance jumping <strong>4.4x</strong>
this time (interestingly we don&rsquo;t see that much difference in the <code>_sum4</code>
variants, see the <a href="/blog/clean-code-rust/#annex-1-benchmark-results">annex for more information</a>). The
lookup table implementation took the performance to new levels with a
performance boost of <strong>6.4x</strong> with the naive <code>for</code> and once again by <strong>11x</strong>
with the <code>_sum4</code> variant.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Even though most of what we seen here is hardcore bit twiddling, being a
&ldquo;Performance-aware Programmer&rdquo; is not a bad thing. Most of the people reading
this (and me writing!) will most likely be developing Software that does not
necessarily needs to make these trade-offs for performance, but that&rsquo;s not the
point, at least not for me.</p>
<p>The point is: <strong>we should be aware of them!</strong></p>
<p>We should always be aware when we&rsquo;re doing trade-offs and we should strive to
learn new things that challenge our status quo.</p>
<p>I&rsquo;ll probably not directly use many of the constructs I went through in this
post in my day-to-day job, but it sure as hell was fun researching and quickly
doing them this Sunday evening!</p>
<h2 id="annex-1-benchmark-results">Annex 1: Benchmark Results</h2>
<p>For all the results we&rsquo;ve seen thus far in this post, I used a
<code>Vec::with_capacity(10240)</code> and the <code>cargo bench</code> command, below you can see the
execution times:</p>





<pre tabindex="0"><code>$ cargo bench -- total_area
   Compiling clean_code v0.1.0 (/home/chrs/Workspace/clean_code)
    Finished `bench` profile [optimized] target(s) in 0.58s
     Running unittests src/lib.rs (target/release/deps/clean_code-3affde07f20d1563)

running 8 tests
test m01_trait::tests::total_area                  ... bench:      54,956 ns/iter (+/- 280)
test m01_trait::tests::total_area_sum4             ... bench:      17,725 ns/iter (+/- 1,373)
test m02_match::tests::total_area                  ... bench:      17,141 ns/iter (+/- 304)
test m02_match::tests::total_area_sum4             ... bench:       6,434 ns/iter (+/- 5,001)
test m03_table::tests::total_area                  ... bench:       8,560 ns/iter (+/- 169)
test m03_table::tests::total_area_sum4             ... bench:       5,734 ns/iter (+/- 1,005)
test m04_table_multiplier::tests::total_area       ... bench:       8,555 ns/iter (+/- 29)
test m04_table_multiplier::tests::total_area_sum4  ... bench:       5,002 ns/iter (+/- 82)

$ cargo bench -- corner_area
    Finished `bench` profile [optimized] target(s) in 0.01s
     Running unittests src/lib.rs (target/release/deps/clean_code-3affde07f20d1563)

running 8 tests
test m01_trait::tests::corner_area                 ... bench:      54,302 ns/iter (+/- 233)
test m01_trait::tests::corner_area_sum4            ... bench:      35,922 ns/iter (+/- 563)
test m02_match::tests::corner_area                 ... bench:      12,160 ns/iter (+/- 2,019)
test m02_match::tests::corner_area_sum4            ... bench:      12,128 ns/iter (+/- 41)
test m03_table::tests::corner_area                 ... bench:       8,554 ns/iter (+/- 23)
test m03_table::tests::corner_area_sum4            ... bench:       5,736 ns/iter (+/- 15)
test m04_table_multiplier::tests::corner_area      ... bench:       8,547 ns/iter (+/- 10)
test m04_table_multiplier::tests::corner_area_sum4 ... bench:       4,995 ns/iter (+/- 6)

test result: ok. 0 passed; 0 failed; 0 ignored; 8 measured; 8 filtered out; finished in 5.24s</code></pre><p>You&rsquo;ll see a <code>m03_table</code> that has been omitted on the blog post just due to it
being very similar to the <code>m04_table_multiplier</code>, the <code>m03</code> module was my first
naive translation of the lookup table optimization (I&rsquo;ve left in the gist if
you&rsquo;re curious).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Respawn</title>
      <link>https://chrs.dev/blog/respawn/</link>
      <pubDate>Sun, 31 Mar 2024 00:11:00 -0300</pubDate><author>christian@chrs.dev (Christian Mutti)</author>
      <guid>https://chrs.dev/blog/respawn/</guid>
      <description>I&amp;rsquo;ve been recently been bit with the writing bug again, but I don´t know how long this will last (you can check for yourself how long ago was the last post on this blog, and more importantly it was the only one that survived).&#xA;Reading my previous post had me thinking about my career so far and how writing can preserve my thoughts at a point in time, and generally make for a pretty interesting read on the future.</description>
      <content:encoded><![CDATA[<p><img alt="Bernie Sanders, writing on the bottom says &ldquo;I am once again trying to write more on my blog&rdquo;" src="/images/02-respawn-once-again.webp"></p>
<p>I&rsquo;ve been recently been bit with the writing bug again, but I don´t know how
long this will last (you can check for yourself how long ago was the last post
on this blog, and more importantly it was the only one that survived).</p>
<p>Reading <a href="/blog/lessons-learned/">my previous post</a> had me thinking about my
career so far and how writing can preserve my thoughts at a point in time, and
generally make for a pretty interesting read on the future. My memory isn&rsquo;t the
best, and I tend to think writing to bve the best medium to preserve my thoughts
for myself.</p>
<h2 id="the-year-is-2019">The year is 2019</h2>
<p>At that time, I was employed at Biggy, working with e-commerce recommendation
engines, which was my first <em>real</em> programming job, as stated in that post. I&rsquo;m
still at the same company <em>kinda</em>. That year was also a pivotal moment in my
career, and Biggy&rsquo;s journey, being exactly the year when it was acquired by
<a href="https://vtex.com">VTEX</a>, my current employer.</p>
<p>That year also marked several personal milestones: I traveled abroad for the
first time (twice!), my nephew was just born (he&rsquo;s now almost 5 years old) and
the world was yet to see what the word pandemic meant. My first international
trip was also something I wish I had a better recollection of, as it was part of
my interview process for <a href="https://spotify.com">Spotify</a>, which ended with me not
landing the job, but learning a lot throughout the process.</p>
<h2 id="fast-forward-5-years">Fast-forward 5 years</h2>
<p>If I answered &ldquo;how do you see yourself in 5 years?&rdquo; back then, would the answer
be close to the reality of today? Mostly no. But that doesn&rsquo;t mean I didn&rsquo;t
accomplish things I was hoping for, it actually means I accomplish things I did
not foresaw. This may be an improvement or not, I won&rsquo;t get too hanged up on
that.</p>
<p>A big part of that journey was due to VTEX and the people I work with on a daily
basis. Being part of a welcoming team and working with interesting problems made
it very difficult to accept any huge changes (and there were opportunities for
some of those).</p>
<p>Something that held me in place for some time was my academic journey.
Graduating for me was a slow process, as I was already working, sometimes I got
very disgruntled with the classes and assignments. It was actually the pandemic
that made me focus a bit more in my studies, but the full-fledged graduated
status only came in the near end of those 5 years.</p>
<p>Living abroad has been a big dream of mine, and maybe the strongest difference
from my ideal self of 5 years ago. I hadn&rsquo;t been giving that much thought to
this since recently, and it&rsquo;s something that I&rsquo;m setting my eyesight on for the
near future.</p>
<h2 id="what-does-the-next-5-years-hold">What does the next 5 years hold?</h2>
<p>I can&rsquo;t predict the future, but I&rsquo;m certain my current actions will help shape
it, and one thing that I can do is control my current actions. My last years
have been a cruise in order to reach some sort of financial security, and I few
that the time has come to lean on that security and take more risks.</p>
<p>I&rsquo;m pretty confident that the work I like to do is coding, as simple as that,
and I&rsquo;ll try to optimize this on the opportunities going forward. That means I&rsquo;m
most likely not follow a management path in the near future, and set my sights
on improving myself as a specialist. This has been something that I&rsquo;ve poured a
lot of thought into, and I find myself more certain than ever about this path.</p>
<p>Another thing that is crucial to me is self-improvement through working on my
body. There are lots of people out there that have given general wisdom about
mind and body being connected, so I won&rsquo;t be adding much to that discussion (and
I don&rsquo;t have significant knowledge to do so). But what I can say is that working
out and practicing sports has been a beneficial hobby, for my mind and body.</p>
<p>And I dare finish with: <strong>I should write more</strong>. I like writing and, moreover, I
like reading my thoughts at a later point. So Iĺl try to document what I find
interesting and have been working on as learning projects, but also, maintaining
a healthy check-up of what is on my mind.</p>
<hr>
<p>This should&rsquo;ve probably be a disclaimer at the top, but I&rsquo;ll leave it here: the
writing here is the definition of rambling. I wrote what came up at the top of
my head without much thought, and this will probably have use only for me in the
future.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Lessons Learned in 2 years as a Software Developer</title>
      <link>https://chrs.dev/blog/lessons-learned/</link>
      <pubDate>Fri, 21 Jun 2019 17:00:00 -0300</pubDate><author>christian@chrs.dev (Christian Mutti)</author>
      <guid>https://chrs.dev/blog/lessons-learned/</guid>
      <description>I&amp;rsquo;ve been interested and learning programming for most of my life, since I was 11 years old tinkering with RPG Maker and dreaming of being a full time game developer.&#xA;Fast-forward 12 years in the future, two years into the best job I could ever hope for, a lot learned along the way and a lot more to learn in the future. Two years might not seem like a lot, but working for a startup made a lot of difference, being exposed to new technologies and having people to support me while I was learning.</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve been interested and learning programming for most of my life, since I was
11 years old tinkering with
<a href="https://www.google.com/search?q=rpg+maker+xp&tbm=isch">RPG Maker</a> and dreaming
of being a full time game developer.</p>
<p>Fast-forward <strong>12 years in the future</strong>, two years into the best job I could
ever hope for, a lot learned along the way and a lot more to learn in the
future. Two years might not seem like a lot, but working for a startup made a
lot of difference, being exposed to new technologies and having people to
support me while I was learning.</p>
<h2 id="knowing-that-you-dont-know">Knowing that you don&rsquo;t know</h2>
<p>Looking back with the power of hindsight my biggest lesson was that <strong>there is</strong>
<strong>so much I don&rsquo;t actually know</strong>. At that time I had been programming for 10
years, <em>if you call the first few years as actually programming</em>, I had tested
the waters with Java, C, C++ and occasionally web development.</p>
<p>The main focus of most of my time learning was to create a game that I would
enjoy and call mine, quite common among gamers that go into programming. But a
mistake I repeated time and time again was to doubt my own abilities. I would
start over <strong>100 times</strong>, trying to find a better solution, watched <em>hundreds</em>
of videos and tutorials, but always beginner level, and that was my biggest
mistake, not exposing myself to more advanced programming made me stagnant for a
long time.</p>
<blockquote>
<h3 id="do-or-do-not-there-is-no-try">Do&hellip; or do not. There is no try.</h3>
<p>* <em>Tutorials are great, but actually doing stuff is even better.</em></p>
</blockquote>
<p>The tipping point of my programming career came in the form of <strong>Open Source</strong>
<strong>software</strong>, two years into my undergrad I enrolled in a program to &ldquo;foster
open source software development&rdquo;, that was the first time I had to tackle a
codebase larger than a dozen files, with a clear goal and being exposed to code
that wasn&rsquo;t written by me. A couple months after that I landed my first <em>real</em>
programming job.</p>
<h2 id="knowing-how-to-search-what-you-dont-know">Knowing how to search what you don&rsquo;t know</h2>
<p>One of the most important tools of the job has to be Google (<em>or DDG!</em>), but
it&rsquo;s one of the hardest to actually get it right, <strong>knowing what and how to</strong>
<strong>ask something</strong> is actually more important than trying, and failing, to know
everything by heart, don&rsquo;t get me wrong, there are a lot of tasks that are
deeply ingrained in your memory and you will be able to correctly execute them
till the end of your life, but <em>the rest you should google</em>.</p>
<p>So, <strong>how do you look for something online</strong>? My first instinct when I try to
find something is to actually find <em>someone</em> that went through the problem I&rsquo;m
having right now and how they fixed it, most likely ending up reading a question
in <a href="https://stackoverflow.com">Stack Overflow</a>. The search query could be either
the error message or an imagination of how that question would be asked by
somebody else, like
<a href="https://www.google.com/search?q=how+to+pad+strings+in+javascript&oq=how+to+pad+strings+in+javascript">&ldquo;how to pad strings in javascript?&rdquo;</a>.
These types of questions will most likely yield better result when you know very
well <strong>what you&rsquo;re trying to accomplish</strong>, and sometimes knowing lingo, and
that&rsquo;s the <em>hardest</em> part.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
