<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~files/feed.xsl"?>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" version="2.0">
  <channel>
    <feedpress:locale>en</feedpress:locale>
    <feedpress:newsletterId>benmccormick</feedpress:newsletterId>
    <atom:link rel="hub" href="http://feedpress.superfeedr.com/"/>
    <title>benmccormick.org</title>
    <link>http://benmccormick.org</link>
    <description>A blog by Ben McCormick</description>
    <lastBuildDate>Wed, 01 Jan 2020 16:26:46 GMT</lastBuildDate>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>Feed for Node.js</generator>
    <image>
      <title>benmccormick.org</title>
      <url>https://benmccormick.org/logo.png</url>
      <link>http://benmccormick.org</link>
    </image>
    <copyright>All rights reserved 2016, Ben McCormick</copyright>
    <atom:link href="http://feedpress.me/benmccormick" rel="self" type="application/rss+xml"/>
    <item>
      <title><![CDATA[Fun with Ascii: Putting some console art on my site]]></title>
      <link>https://benmccormick.org/ascii-kusty</link>
      <guid>https://benmccormick.org/ascii-kusty</guid>
      <pubDate>Wed, 01 Jan 2020 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>I’ve always enjoyed sites that had easter eggs in their consoles, whether they’re simple and whimsical like Ponyfoo.com</p>
<p><a
    class="gatsby-resp-image-link"
    href="/static/bc30390af4e06b9340a4f34c5e77c434/d40c8/ponyfoo.png"
    style="display: block"
    target="_blank"
    rel="noopener"
  >
    <span
    class="gatsby-resp-image-wrapper"
    style="position: relative; display: block;  max-width: 570px; margin-left: auto; margin-right: auto;"
  >
    <span
      class="gatsby-resp-image-background-image"
      style="padding-bottom: 69.4%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAACGUlEQVQ4y6VU247TMBD18/4CD4hP4R3Ef/RbkOArkFbLK3wE2u4WiZWoeqVNk9RxYsd2bm3js+O0KV0kJC4jnczFM+NRziSsriqUZYk0y7AKAiRSItcatiigjUFu9BnKa6vBUwGZKygPbcFVgSSVUEKA1VUBS4lFoVEVOSoRod1ZCL6C0ZyackgdIzMxhImwNSFiG2KrQro8otoMtVHYUY+9MmD7wwEHQuscGltg+vkTrq8/YDQawct+v0fbUs4lfH7bHuNk+5wezD/quu6K3719j6vnV3jx8hmyrexiu93uScHvcDgN1jWs6D16GQwGYIzh9ZtXiKLoPGGf3E926fc4T9gneHl4+IaPNzcYfx93viVSdJ4jJ2hPlDWQRJ7xZClFWndndVPTRQ6tn1DRgS9SuSEWS5R1QyyTTchUfoRUxGIGkcnO9hDkq1yjrGoUxqLQEsZasMlkiul8jngxQbacgM8mUKs5qiRCxUPUcQAbBZAU08EP2JTDZAkMaS04+GYNEQaIVwukcQi2WcwwHk+h+BiNGEKsh5CbO6TBEFlw18Hb6fr26G/uIaOvlHcLQfGE8uPlF/DgHo1ZgoXrFWazGYrqyHTb7uHccSVad/hpn3yv3Ul7AI62pKIPwdBGNGA8SRHFW1rsAv8i7hefecY8+l10tOD/A+bXoaP+1PDJ7c799cRdQ4/uB5GmkPRz8NrSClxO/KfyCKL6KxcSGcYGAAAAAElFTkSuQmCC'); background-size: cover; display: block;"
    ></span>
    <img
        class="gatsby-resp-image-image"
        style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;"
        alt="Ponyfoo has a "welcome adventurer" message in their console"
        title=""
        src="/static/bc30390af4e06b9340a4f34c5e77c434/a9e6e/ponyfoo.png"
        srcset="/static/bc30390af4e06b9340a4f34c5e77c434/40f08/ponyfoo.png 143w,
/static/bc30390af4e06b9340a4f34c5e77c434/d4502/ponyfoo.png 285w,
/static/bc30390af4e06b9340a4f34c5e77c434/a9e6e/ponyfoo.png 570w,
/static/bc30390af4e06b9340a4f34c5e77c434/c2e96/ponyfoo.png 855w,
/static/bc30390af4e06b9340a4f34c5e77c434/f4f98/ponyfoo.png 1140w,
/static/bc30390af4e06b9340a4f34c5e77c434/d40c8/ponyfoo.png 2000w"
        sizes="(max-width: 570px) 100vw, 570px"
      />
  </span>
  </a></p>
<p>or practical like Facebook’s </p>
<p><a
    class="gatsby-resp-image-link"
    href="/static/18f8473330556eccf15a6bf869f37e5a/7554f/facebook.png"
    style="display: block"
    target="_blank"
    rel="noopener"
  >
    <span
    class="gatsby-resp-image-wrapper"
    style="position: relative; display: block;  max-width: 570px; margin-left: auto; margin-right: auto;"
  >
    <span
      class="gatsby-resp-image-background-image"
      style="padding-bottom: 60.739260739260736%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAACsUlEQVQoz5WTy4sUVxTGS3DjxlV2+VsixE3QVZJFFhpmISIBSTSD/4ELMyjOWsUHuglEk2iCQdDxDfNQZhymu6d6umeqna73o7u63tXd88upEiTgKhc+zr2Xe79zvu/cq0zKnDTLcD2Pvq7j+T6jOCaKkxqjKCLPM6aTnL1pyWRcMC5T8iyCvbI+60UxeRqxN85QHi/usPTuPastk/W2zZrEtw2dNxt9gS5rnd8eNTh/ZZG5m8vM31jg8u0VLt5a5pLgwtWXzF17wdz118zfWUG5/+gNz5fbLK5pQrDLihCtNg3WVYt3gnXV5PmKxr3HKn88UXmw0OTPhTb3BQ9f7vDPqx2JXf5+sc3vTzoojU4PQ+/X0gaBz8bqEqXYMJ2UIq0Apnw69rh08RdmZo4xe+4ss7NnOXXqJGd+/kkqfKXS3epguwMsx6eltknTTHwtiJOMoigosoQkzckL8XA6lYQTvjj8FYqioOw/gLJvfz0/+NnnKGsNlV5PxxYyfxDiDIcEwQA/THC8IaNwSBhYMg9EhZifl2R5wdGvv+PQkW84eWaW7384zbETP/Ltl8dRNO09ruthWi493cEwLIZhSDQaEVZkEofhSOwIGEoyzw+wbJenz56x0WiQJIkoyEjkzNKyNGWr00Ftt3Edh5FcGsiziYWkkpplHyRHlb+DAbE8kYogTROmIj3P83qvuhv4niQeohjbHTrdLqFjEz68S/DXr5R9jf8zxuOx+FrWUPTdXbRe70Mmy8LUdrBMUzx1a5iWjVNbYtePv94zLaxqLfuGzDWtV9uRpimKZXviiVPLaqpbtLa6qILWZpt2p0uzpdIQbDQ32e3rH8ltkekIuev5dZLqh1UWKXEcffTGkUOGfD/DMOj3+1KJiS7rKvpV58VjX5pSiLT/jqp5VUFVhf8CEp9WPtXli+cAAAAASUVORK5CYII='); background-size: cover; display: block;"
    ></span>
    <img
        class="gatsby-resp-image-image"
        style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;"
        alt="Facebook warns people about scams in the console"
        title=""
        src="/static/18f8473330556eccf15a6bf869f37e5a/a9e6e/facebook.png"
        srcset="/static/18f8473330556eccf15a6bf869f37e5a/40f08/facebook.png 143w,
/static/18f8473330556eccf15a6bf869f37e5a/d4502/facebook.png 285w,
/static/18f8473330556eccf15a6bf869f37e5a/a9e6e/facebook.png 570w,
/static/18f8473330556eccf15a6bf869f37e5a/c2e96/facebook.png 855w,
/static/18f8473330556eccf15a6bf869f37e5a/f4f98/facebook.png 1140w,
/static/18f8473330556eccf15a6bf869f37e5a/7554f/facebook.png 2002w"
        sizes="(max-width: 570px) 100vw, 570px"
      />
  </span>
  </a></p>
<p>I’m also part of a <a href="https://www.kustomer.com/">fast growing company</a> and we’re always hiring, so I thought I’d see if I could leave a fun message in the console, and play around with ASCII art while I was at it.  </p>
<p>Kustomer’s logo is <em>Kusty</em>; a smily speech bubble with apostrophes for eyes:</p>
<p><a
    class="gatsby-resp-image-link"
    href="/static/80799b63db397c007bcc85e9d9bc4c17/3b243/logo.png"
    style="display: block"
    target="_blank"
    rel="noopener"
  >
    <span
    class="gatsby-resp-image-wrapper"
    style="position: relative; display: block;  max-width: 570px; margin-left: auto; margin-right: auto;"
  >
    <span
      class="gatsby-resp-image-background-image"
      style="padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABIElEQVQoz2NgoAX4HxnK8KOrnflLXzfz/9JCRpCYCBcXAyM5hn0xNyKkhBGKkdkgzIRGIxlqoM32v7Is9n9tVcHf6Ag5kJiBsBAb+V6uLHW7uXXL/ztnz/7/P292J1DIjo2NLRFISwOxHhDbA3EQEFsBsTEQOwOxH5TvBlIPxBIIA+ur3e9t3/b/8tEj//8vX9IDFLJmZ2ePAdLhQJwLxAlAHAfF0UAMkvMC4hIgLgDiCCDmRxjIx8Hxv7cr4feKZcX/w4IUQWLusjIsQEoSiIWgmBMUV0AsCA03ViBmg8ohgue/gTZmEPz/T2GyMdFn+D1vDvOPfXuZ/yfFg2NMgZ+fASP2cKcCBPiXlQ4xNDGW4X9JIcN/dyeIeHoyWY4DADgiT1+U/QKHAAAAAElFTkSuQmCC'); background-size: cover; display: block;"
    ></span>
    <img
        class="gatsby-resp-image-image"
        style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;"
        alt="Kustomer logo"
        title=""
        src="/static/80799b63db397c007bcc85e9d9bc4c17/a9e6e/logo.png"
        srcset="/static/80799b63db397c007bcc85e9d9bc4c17/40f08/logo.png 143w,
/static/80799b63db397c007bcc85e9d9bc4c17/d4502/logo.png 285w,
/static/80799b63db397c007bcc85e9d9bc4c17/a9e6e/logo.png 570w,
/static/80799b63db397c007bcc85e9d9bc4c17/c2e96/logo.png 855w,
/static/80799b63db397c007bcc85e9d9bc4c17/3b243/logo.png 1024w"
        sizes="(max-width: 570px) 100vw, 570px"
      />
  </span>
  </a></p>
<p>So how did I get Kusty showing up in the console on this site?  I started with a bit of a cheat: I asciified the logo using <a href="https://www.asciify.me/">asciify.me/</a>.  That got me a nice starting place, I had an Ascii version of Kusty to work with:</p>
<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"> &#39; ``.&#39;` . -_+&quot;)cTtfyyyszztszszszztzfztfsfzsfzsstttyt17vr&gt;, .   ` &#39;-`- `
  ..`.&#39;`.~)71tyyzzfzfzsyststztyftsytsystyztzzyzsyyytyfsytf1l?!  -.` `&#39;`.
-.- - `+}Tzztsfyffztzzyyztsffyytfyyzztyfzyfzyfystzftszfytfysyt{+--&#39;.- `.
 `--.&gt;Lyffttyztsfyztyt11fYtyyzYTz1yT1yfzfTt1TsYfftsttzzysffssyyt7+  &#39;&#39;`-
 -`!iysttfstffzTi?&quot;+,,!~^~!^__~!_:,:^^^,!~_~~:_,,!:^+/i1zyytfyztzzi~&#39;&#39;-.
. !}tsftzffyTv+~..  -`-.&#39; &#39;. .`-   .&#39;.-- ` ` . -&#39;- .-..~+v1fsfttszf}&lt; . 
 ,xftyyysszv, -. ```&#39; &#39;. .-.``&#39;.-   &#39;&#39;.&#39;--&#39;- &#39;  ` ...&#39;&#39;  .!vytyzsstsx^- 
&#39;/zsstzzzf*` `` &#39;  ` `- &#39;`- ` `.`  -.-   - `.&#39;-- -` - &#39;` &#39;``=1szfyzssi&#39; 
+Yzftsztf? `  `-` ` -- ` &quot;vje4J&gt;&#39; ...` `  &#39;~iteau(.&#39;` `-- ``&#39;/tzszszfY+&#39;
isttsstzl:     `.-  .`&#39;[qQQRgQBt  - `-.&#39; rkDQWRQg6  -&#39;&#39;- `   ^]ffyzstyi&#39;
xyfssytyv&#39;&#39;- .&#39;&#39;-   .:#QBW&amp;j}v+&#39;  &#39;`. `&#39;s@gR@$Lv&quot;-``   - - .&#39;`?ystysztL`
xtyytzsyv .`-.&#39;-  `&#39; JRgBV:...``.&#39; -.  [HWHd+  .&#39;-- `-     &#39;&#39; /ysyzftsl&#39;
cyyfysfyi  &#39;-`&#39;``&#39; -`NBWW^&#39;    .&#39;`` - &#39;2gBQ{`    .-`-&#39;. . `-&#39;.(zsyyzzzL_ 
{ytyztfti    &#39;-`&#39;..&#39;&#39;DBRWSS%9wk&quot;-  .-  nWWHOwE%%5x    `&#39; -  `&#39;|ftzttytx- 
{ttszfysi.`-&#39; `.&#39;&#39; -.DWHgggBRgH2-`.&#39;&#39;  2BWHgWRHgB&amp;&#39; .`. &#39;  . &#39;/sfztfsyc` 
7zzsfsyzi - &#39;`  &#39;&#39; ` &amp;BHgQWRgBHj-&#39;- &#39; &#39;JQWHBBHHHQ@   ` .-```- /ttfttyy7&#39; 
lsfsttfti-&#39;.`  -` -&#39;`DBHgHHRWRHu.. `&#39;`.nWHRgRRBgg&amp;.`&#39;` &#39;`   &#39;-?fsysfss7.
xstfsytti `- `.&#39;&#39;&#39;`.&#39;pBBRQQRBgBn. &#39;&#39; &#39; CQBWBQBBBQO--&#39;`   - -- )sstfzyz] 
}fzztyfsv.  &#39; -   &#39;..+[yfsfyzyv!-    ` !ittfftztc+&#39; &#39;  &#39;  -. &#39;)zzzzstsL`
7ttszfssi&#39;- &#39;-  &#39;`  -``-- - -`` -.-.-`` `` &#39;..- . .&#39;&#39;- .  &#39;.- /sfyyftsL`
{fsyysyzv-&#39; &#39; .-  &#39;`  &#39;    - - -  ```-...&#39; .&#39; -  - .-&#39;`-.&#39;-  `/fstyzszl&#39;
7{yzzyttfi &#39;- &#39;.&#39;.&#39; &#39; &#39; . - - . -&#39;  -&#39;-- &#39;&#39;`  .  -&#39;   `&#39;- .  &#39;`(ffstfss}`
{ztfzttsi -   -&#39; ..&#39;` ``&#39;`.--  .  -. &#39;. .&#39;&#39;&#39;   &#39;  -&#39; -&#39;&#39;.-. &#39; )zssfyzs]-
{tzszzzyi&#39;.&#39;-`.--  &#39; `&quot;&amp;QQQHQWWgHWWgBQWWBggBgWW&amp;/ `` &#39;.&#39; &#39;`- -/zfszzzs}-
xyffzzzsi -.`-`&#39;&#39;&#39;- &#39; &#39;]MHgHRHHgRQHBBWQWHHgBQQO1-`.`&#39;.--. &#39;&#39;` |zzztfysl&#39; 
ittsfsttc^`   -  .&#39;   &#39;`~zMHHQWgBQRQgHQWggHQMt:&#39;&#39; &#39;`- .&#39;   `-,{fttttzzi`
+Yzftsstt|&#39;. .  &#39; .   .  .-vJONHHBWQggBB&amp;MFi. ` &#39; -.  `.&#39;--  \yyzszyf1&gt;`
 /tfyyyzyf&quot;  - `.`&#39;..``  -`- -+\c1f2yTc/&lt;. &#39;``.-`.`&#39;-.&#39;`-&#39;` rfztyssfsi&#39;&#39; 
 :Ltzzytsstv,- ` &#39;.`&#39;  &#39;` &#39; ```- &#39;`    .`.- `&#39;. . - ` ``--,itftfsfyt{,&#39;`  
--^LtfsfsftsYi+:&#39;`-. `  .  .-` - `.--&#39;&#39;`` -   `. ``&#39;`  ~&gt;iTztyyyfzs[&lt; `.
.. ^iftstzzfsssYv)r,^__!_^!!~&#39;.-&#39;. ..- -&#39;&#39; `,_:_~_~:&gt;)i1zsfzsstfzfi!. `-
.`  .&gt;]ytfyyzsyszftsz1TYY1Y11v&gt;-     -.&#39;-&#39;. {TYTTYstzttfzsfftsstl&lt;&#39;   &#39;`
-.-.-. &gt;lfsszzsyytszysyzzzzysfy1?&lt; &#39;       `7zzffsyystzsttztzfx&gt;` &#39; - .&#39;
`.&#39; `&#39;&#39;`.^(c1zfttfztfyssyyffttzyyf}r~.- &#39;&#39;&#39;-7tfyzszzztysfy1L(!-.-`-.`.-`
-&#39;    `&#39; -. !+&quot;([TyyzyzzsztststfsszyYi*_` -`{zyzfzfffT[v&quot;&gt;!&#39;`..`-` .`.-` </code></pre></div>
<p>At this point I could have tossed that into a console.log and called it a day, but I wanted to take this to the next level.  And that means color!</p>
<p>This isn’t something you run into every day while writing for the web, but it turns out that you can apply css to text in the console using a <code class="language-text">%c</code> macro.  The format goes like this:</p>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'%cbold text %cred text'</span><span class="token punctuation">,</span> <span class="token string">'font-weight:bold'</span><span class="token punctuation">,</span> <span class="token string">'color: red'</span><span class="token punctuation">)</span></code></pre></div>
<p>That code outputs <span style="font-weight: bold">bold text</span> <span style="color:red">red text</span>.</p>
<p>Of course its a pain to split that giant Kusty ascii block into multiple console logs with different colors.  So I minimized the pain and wrote a script that would let me take a set of ranges and render characters in one of 3 colors, and using either solid characters <code class="language-text">A-Za-z1-9+{}&lt;&gt;;</code> or space characters <code> `.,_-’</code>. I did eat the cost of writing out the map characters manually based on the generated ascii.  If I was going to do this again, I’d probably write out a script to generate the map from the original ascii image, and just fill in the color mappings manually. </p>
<div class="gatsby-highlight" data-language="js"><pre class="language-js"><code class="language-js"><span class="token comment">//we use these characters for the solid lines</span>
<span class="token keyword">const</span> solidChars <span class="token operator">=</span>
  <span class="token string">'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789+{}&lt;>;'</span><span class="token punctuation">;</span>
<span class="token comment">// and these ones for empty space</span>
<span class="token keyword">const</span> spaceChars <span class="token operator">=</span> <span class="token string">" `.,_-'"</span><span class="token punctuation">;</span>

<span class="token comment">// these maps chars and colors </span>
<span class="token keyword">const</span> chars <span class="token operator">=</span> <span class="token punctuation">[</span>spaceChars<span class="token punctuation">,</span> solidChars<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> colors <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'#E0E0E0'</span><span class="token punctuation">,</span> <span class="token string">'#ED6159'</span><span class="token punctuation">,</span> <span class="token string">'black'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token operator">/</span><span class="token operator">/</span> <span class="token keyword">this</span> is the mapping to generate kusty
<span class="token keyword">const</span> map <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">[</span><span class="token number">13</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token number">45</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token number">13</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token number">53</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token comment">/* etc */</span> <span class="token punctuation">]</span>

<span class="token operator">/</span><span class="token operator">/</span> generate the ascii string <span class="token keyword">from</span> the map
<span class="token keyword">const</span> ascii <span class="token operator">=</span> map<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">agg<span class="token punctuation">,</span> val</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token operator">/</span><span class="token operator">/</span> nulls mean spaces
  <span class="token keyword">if</span> <span class="token punctuation">(</span>val <span class="token operator">===</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> agg <span class="token operator">+</span> <span class="token string">'\n'</span><span class="token punctuation">;</span>
  agg <span class="token operator">=</span> agg <span class="token operator">+=</span> <span class="token string">'%c'</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> characters <span class="token operator">=</span> chars<span class="token punctuation">[</span>val<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token function-variable function">randChar</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    characters<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> characters<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> val<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    agg <span class="token operator">+=</span> <span class="token function">randChar</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> agg<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> colorStrings <span class="token operator">=</span> map
  <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">!==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>
    <span class="token parameter">val</span> <span class="token operator">=></span> <span class="token template-string"><span class="token string">`color:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>colors<span class="token punctuation">[</span>val<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">; font-family: monospace, font-weight: bold`</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>ascii<span class="token punctuation">,</span> <span class="token operator">...</span>colorStrings<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div>
<p>The code is fairly straightforward, going through each segment and generating a string of random characters based on the map.  The interesting parts are probably:</p>
<ul>
<li>We use <code class="language-text">null</code> to denote new lines.  Could have been anything, but null is pretty obvious when you write out the mapping markup.  </li>
<li>I usually use lodash for this, but I wrote some custom code to pull a random item from an array:
<code class="language-text">const randChar = () =&gt; characters[Math.floor(Math.random() * characters.length)];</code></li>
<li>I added a rare for loop in JavaScript code: even though map/filter/forEach etc work better for most things, a for loop is still the best way to do things when you’re given a number of times you want something to occur.</li>
</ul>
<p>It works pretty well!</p>
<p><a
    class="gatsby-resp-image-link"
    href="/static/9ded1afd1d1509a486545a308418b312/796f5/console-kusty.png"
    style="display: block"
    target="_blank"
    rel="noopener"
  >
    <span
    class="gatsby-resp-image-wrapper"
    style="position: relative; display: block;  max-width: 570px; margin-left: auto; margin-right: auto;"
  >
    <span
      class="gatsby-resp-image-background-image"
      style="padding-bottom: 91.68260038240918%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAABYlAAAWJQFJUiTwAAACx0lEQVQ4y51Uy27UQBD0Z/IBiBN3lC+AL+DGiUvOXHJDHKIgBSEugTx2s6/Ya68f67c99nhcVI8TlESESHjVmp7ecXV1dY+duizR1DXCMIK33dJ8pFmOLC+Q878sp1/QL0obKxjbp5m1kn6vFJZugDAtUGYpnKqukDcKRavQdj0GrdG2LRQPit33J+vQNI2Na54VG4cBoxlgzAinJFDYjdgpg7xjcNAYeOBfdpdoMgU9Aqrr0NGcuqpQ5hmKLLP0jTHPAprh9gzPtlUB7/wHqjQBCcIpqE8UxfCpXU5fsjwsUdlYK6xYrrCqmxqNailPh9XxET68fonDdwfo2mbS0Au3cHcefJ/rjYvNZgPXnVbP8+DSYs9F4XvI0hRJsUda59CqwfrbFxwevMHbVy9QkKVTs8OqUzZrVU9ii+gSF2sYk71i9p4mbHWvbXPGXuF7kOH9x084+nyMkT/nerGwLHa7EO52Z/0wDJFT0zTdI+MoyN7ztoji2PpRFCEIAsTcx3GCKEk5QjkC34czu7zC+a9zxEkCn4e8YMcDBCoVknxArdhVjobiSN11VhiLdbed1X0/VUGdnWC9wHq1tG23Hd4nGKiV5pD37rQa7g0n4alnHEcmoiQEdlY3HtYb12Y2gY/+eg6TxBhZqiG4rFriVxcYJH4L8NiEjKyO6CSj07Lb+noGw0ZUHNY1u9xz3raUoWUTDLurl9cWEI9A7z/Ofr9HyeFWvJd6tZCTdmTmsxly3uOfZ2eTHJJws/oDcB/sPrgFlAuvysIyIHfcEPD09JQdzvD15MR+CCCAy8UD3f72TIDCkGUPUhKFrVi2xOV6yYi0wtAm/A9AYy9/h/l8jjOWu1ouMfDlgUn0evmgzKcBpWTOkQAO7Kow23JILy4vLVPDT9MQhdA36zt6zwCSnWKpMmt6PqP4fJEjInqiqqy2YgP98RnA30n+ZDpHr3AnAAAAAElFTkSuQmCC'); background-size: cover; display: block;"
    ></span>
    <img
        class="gatsby-resp-image-image"
        style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;"
        alt="A picture of the console"
        title=""
        src="/static/9ded1afd1d1509a486545a308418b312/a9e6e/console-kusty.png"
        srcset="/static/9ded1afd1d1509a486545a308418b312/40f08/console-kusty.png 143w,
/static/9ded1afd1d1509a486545a308418b312/d4502/console-kusty.png 285w,
/static/9ded1afd1d1509a486545a308418b312/a9e6e/console-kusty.png 570w,
/static/9ded1afd1d1509a486545a308418b312/c2e96/console-kusty.png 855w,
/static/9ded1afd1d1509a486545a308418b312/f4f98/console-kusty.png 1140w,
/static/9ded1afd1d1509a486545a308418b312/796f5/console-kusty.png 2092w"
        sizes="(max-width: 570px) 100vw, 570px"
      />
  </span>
  </a></p>
<h3>Next Steps</h3>
<p>Now that I’ve done this it would be pretty easy to reuse this code to create a terminal Kusty with <a href="https://github.com/chalk/chalk#readme">chalk</a>. Maybe next New Years.</p>
<p>For everyone else, if this seemed fun to you, you might be interested in the <a href="https://boards.greenhouse.io/kustomer">job openings at Kustomer</a>.  Feel free to apply or reach out to me directly if you’re interested in working with us.  </p>]]></content:encoded>
      <author>ben@benmccormick.org (Ben McCormick)</author>
    </item>
    <item>
      <title><![CDATA[2019 Roundup]]></title>
      <link>https://benmccormick.org/2019-roundup</link>
      <guid>https://benmccormick.org/2019-roundup</guid>
      <pubDate>Tue, 31 Dec 2019 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>2019 was the 6th full year of this blog, and it was a bit up and down posting wise.  For the first half of the year I published more or less a post a week, with 24 posts from January till July.  But this is only my 2nd post since then.  </p>
<p>Turns out that starting a new job while learning to be a parent sucks up a lot of time!  I’m not making any promises for 2020, but I expect that my writing rate will fall somewhere in between the first 7 months and last 5 months of 2019.  In the meantime, here’s a brief look back at the year on the blog.</p>
<p>This was my first year where I spent the full year managing people, and that was reflected in the blog’s topics as well as where I spent my time.  </p>
<h3>Most Read Posts Published in 2018</h3>
<ul>
<li><a href="https://benmccormick.org/2019/02/11/reusable-react">Reusable Code In React: Inheritance, Composition, Decorators and Mixins</a> The most popular post for the year was also one of my favorites: a dive into the various mechanisms React provides for reusing code.</li>
</ul>
<ul>
<li>
<p><a href="https://benmccormick.org/2019/01/28/readable-async">Improving Code Readability With Async/Await</a> I really like <code class="language-text">async/await</code> but its not always clear how to move older patterns to use it.  This was just a quick example of taking some ugly callback code and converting it to use async await.</p>
</li>
<li>
<p><a href="https://benmccormick.org/2019/01/07/the-concerns-of-fe-architecture/">What’s involved in Front End Architecture?</a>
Another one of my favorite posts to write, this is a look at what types of things developers should be thinking about when they consider front end architecture.</p>
</li>
</ul>
<h3>Languages and Libraries I used a lot of in 2019</h3>
<p>JavaScript (ES6), React (including hooks), PostgreSQL, lodash, Jest, Immer, CSS Modules, Redux, </p>
<h3>Tech I want to try in 2019</h3>
<p>We’re starting to roll out TypeScript at <a href="https://www.kustomer.com/">Kustomer</a> and I’m excited to use it in production for the first time.  My code time is more limited these days, so that will probably be my main area for learning as I focus more on helping other people get stuff done.</p>
<h3>Blogs I started following in 2019</h3>
<ul>
<li><a href="https://lethain.com/">Irrational Exuberance! by Will Larson</a> - a great engineering / technical leadership blog</li>
</ul>
<h3>Blogs I read every post from in 2019</h3>
<p><a href="https://overreacted.io/">Overreacted by Dan Abramov</a>, <a href="https://larahogan.me/">Lara Hogan’s Engineering Leadership blog and newsletter</a>, <a href="http://randsinrepose.com/">Rands In Repose</a> </p>
<h3>Software I used (nearly) every day in 2019</h3>
<p>MacOS/iOS, Google Search, Chrome/Safari/Firefox, GMail/MailPlane 3, Twitter/Tweetbot, Feedbin/Reeder, iMessage, Slack, Jira, 1Password, VS Code, iTerm, Fish Shell, Github/Bitbucket, Fantastical, Spotify, Bear, CloudApp, Dash, Postman</p>
<h3>Best Technical Books I read in 2019</h3>
<ul>
<li><a href="https://amzn.to/35j1Jq1">The Pragmatic Programmer 20th Anniversary Edition</a> - A huge update from the 1st edition, this remains my #1 book recommendation for any professional software developer</li>
<li><a href="https://amzn.to/2QhpkTH">Accelerate</a> - A great look at the impact improving devops/release practices can have on software teams/companies</li>
</ul>
<h3>Best Technical Leadership Books I Read in 2019</h3>
<ul>
<li><a href="https://abookapart.com/products/resilient-management">Resilient Management</a> - A great collection of management wisdom from Lara Hogan.  Nothing revolutionary here for those who already follow her blog/newsletter, but its great to have it all together in one place.</li>
<li><a href="https://amzn.to/2QyJLKM">The Manager’s Path</a> - A super helpful book for anyone thinking about their career path in tech, especially if they’re considering management.  Lots of helpful tips for those already managing people as well.</li>
<li><a href="https://amzn.to/2ZHbFbx">An Elegant Puzzle</a> - Another “blog book”, this one is a bit of a grab bag of topics, but the content is so high quality it was completely worth it.</li>
<li><a href="https://amzn.to/2Fc4izu">Turn The Ship Around</a> - Not tech-specific, but one of the best books on leadership I’ve read, in the form of a history of a nuclear submarine crew getting ready to deploy.</li>
</ul>
<h3>Best Non-Technical Books I read in 2019</h3>
<ul>
<li><a href="https://amzn.to/369CpDX">I Hear You</a> - A small practical book on validation that will make you a better friend / spouse / coworker.</li>
<li><a href="https://amzn.to/2ZHuM52">Why We Sleep</a> - A fascinating book on the (pop) science behind sleep</li>
<li><a href="https://amzn.to/2ZH3bRR">Team Of Rivals</a> - A very readable history of the Lincoln presidency focused on his relationships with the other candidates for President in 1860. Incredibly well done.</li>
<li><a href="https://amzn.to/2MH6F1e">Evicted: Poverty and Profit in the American City</a> - A sobering look at how laws, norms and expectations around rentals and evictions in America contribute to spirals of poverty.  Another very well written book, make sure to read the end to understand the research that went into it and allowed for the very personal feel.</li>
<li><a href="https://amzn.to/2sFrDqz">The Common Rule</a> - This is a Christian look at how ritual and habit can help us overcome modern distractions and focus on the things that are important.  I’ve read a lot of books in this genre in recent years (Deep Work / Indistractable / The Tech Wise Family) and this was my favorite.</li>
<li><a href="https://amzn.to/2QyKhsc">The Foundation Trilogy</a> - Classic scifi, and a great read. Fascinating to read a mid 1900s view of the future and realize that while space travel and force fields sounded great, it was inconceivable that casual tobacco use in the home might go away. </li>
</ul>]]></content:encoded>
      <author>ben@benmccormick.org (Ben McCormick)</author>
    </item>
    <item>
      <title><![CDATA[How Software Engineers Produce Value]]></title>
      <link>https://benmccormick.org/how-se-add-value</link>
      <guid>https://benmccormick.org/how-se-add-value</guid>
      <pubDate>Wed, 18 Dec 2019 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>I had the opportunity this week to walk a software engineer who is new to the field through some lessons I’ve learned over the years about how software engineers add value to the business.  It seemed generally applicable, so here’s a cleaned up version of what I shared.</p>
<hr>
<h2>What Is Value?</h2>
<p>It can be easy to think of software engineering work as a series of task where you’re given instructions and you make the computer do what the designer / PM / CEO asked.  Or as a series of fun problem solving challenges that you’re somehow getting paid to complete.  Both of those views will eventually lead you to make suboptimal decisions when it comes to helping your business and growing in your role though.  Instead consider the following definition:</p>
<blockquote>
<p>Software Developers create value through shipping working code that solves important user problems in a predictable manner.</p>
</blockquote>
<p>This captures a number of important things.</p>
<h3>Shipping</h3>
<blockquote>
<p>Real Artists Ship - <em>Steve Jobs</em></p>
</blockquote>
<p>Software Engineer’s super power compared to other roles is that we get to build.  We create new things, add new behaviors, and ultimately (for a product company) control the shape of the product our company is built around.  This only has value when software actually ships though.  When we’re not shipping, it’s actually worse than just being slow to deliver value, because of a few non-obvious factors.</p>
<p>First, <strong>unshipped code rots.</strong>  When we leave code in a branch 90% done, it doesn’t just stay the same.  It’s quite common for our situation to get worse.  Our teammates check in code that may cause merge conflicts, or worse just doesn’t take into account the unshipped code and sets us up for subtle bugs.  And when we do get back to the work we’ve often lost valuable mental context that makes any remaining work or testing harder and more error-prone.</p>
<p>Second, <strong>we learn from shipping!</strong>  It’s quite common in software development for a developer or team to complete 90% of their feature according to the spec, only to find that they have another 90% of the work to go.  Doing the work to push things through to production inherently de-risks things, because we learn what the challenges are, and we know how long the work took.  Up until then, we will always have unknowns.  And when software goes out to users, we get to hear their feedback as well.  Shipped software lets us learn from our users (and from the performance of our system) and make adjustments that we wouldn’t have known about if we sat on the code.  </p>
<p>So how do we get to shipping?  First, it’s important to push things through to completion rather than allowing ourselves to jump from project to project, making progress without finishing, and incurring a lot of cost from context switching.  Soemtimes this may mean imposing kanban style <a href="https://lethain.com/limiting-wip/">work in progress limits</a> on ourselves.  Second, its often helpful to break things into smaller chunks.  Small code reviews are easier to complete, test, <a href="https://benmccormick.org/2019/04/22/better-code-feedback">review</a> and verify.  So multiple small changes will often go through faster than the same changes bundled together into a big chunk.  This can go too far, but as long as your changes work in isolation and provide value, I’d encourage erring on this side when in doubt.</p>
<h3>Working Code</h3>
<blockquote>
<p>[We Prefer] working software over comprehensive documentation - <em>The Agile Manifesto</em></p>
</blockquote>
<p>Software engineers are responsible for their code working.  At the simplest level that means delivering code that doesn’t crash when run in the intended way.  As we grow and mature as developers however, we should aspire to  learn to write code that will scale to any reasonable load the system might see (and maybe even to unreasonable loads), code that handles odd input or context gracefully, and code that is easy to modify and maintain.  We should also take responsibility for proving that it works; writing tests, making the code easy to monitor in production, and providing good logging for debugging all fall under a software engineer’s domain. We also should make sure that our definition of working matches what the business needs, not just a pedantic reading of whatever spec we’re working off of.  More on that in a moment.</p>
<h3>Solving Important User Problems</h3>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Just really funny- What the Customer Wanted expanded <a href="https://t.co/kdr7HKTSDy">pic.twitter.com/kdr7HKTSDy</a></p>&mdash; Frank Spillers (@farreaching) <a href="https://twitter.com/farreaching/status/764256002053025792?ref_src=twsrc%5Etfw">August 13, 2016</a></blockquote>
<p>Software Engineers can be quite inventive in the ways they write code without solving important user problems.  Some common routes:</p>
<ol>
<li><strong>Working on their own pet projects over the prioritized business problems</strong> - Tech improvement work and engineer-driven projects are part of a healthy organization, but if they consistently replace work that was scoped based on user requests / feedback, they can cause problems</li>
<li><strong>Matching the spec without solving the original problem</strong> - This is partially a design/product problem, but its often possible to meet all the stated requirements for a project without solving the original user pain point.  Great engineers understand exactly what problem they’re trying to solve with a feature and will always step back to evaluate whether they’re succeeding throughout the development process.</li>
<li><strong>Matching the spec and causing new problems</strong> - Oftentimes our efforts to fix cause or expose new problems.  When we dodge responsibility by ignoring or hiding those problems instead of openly evaluating tradeoffs or working to improve the solution, we’re not providing all the value we’re capable of. </li>
</ol>
<p>These are ultimately issues of ownership. When we’re invested in our work, we will want to work on useful problems and make sure they produce real value.  If you’re consistently not feeling that way, it may be time to find something else to work on.</p>
<h3>In a predictable manner</h3>
<blockquote>
<p>The challenge and the mission are to find real solutions to real problems on actual schedules with available resources - <em>Fred Brooks</em></p>
</blockquote>
<p>Ok, now we come to the section that is the <em>boring part</em> for many software engineers.  But as somebody who has recently converted to the management side of the fence, the ability to ship predictably is incredibly important.  </p>
<p>It’s important for software engineers to ship predictably in 2 senses:</p>
<ol>
<li>There is ongoing understanding of when something is likely to ship among the people who need to know</li>
<li>There is ongoing understanding of how something will work when it will ship among the people who need to know.  </li>
</ol>
<p>Estimating software engineering projects is not an exact science. Nobody reasonable expects estimation perfection from software engineers, especially those new to the field.  Instead we aim to be as accurate as possible, and especially to be transparent as those estimates change over time.  </p>
<p>When we encounter obstacles, it’s important to be realistic about what they mean to schedules and update the important people in a timely manner. </p>
<p>For those working on a product team that may be a manager and a PM, for those building something solo, that may be the customers or internal users of the software directly.  It’s never fun to say something is going to be late, but its always better to say that we’ll miss a date that is 2 weeks away than to tell somebody for the first time that you’ve missed the date that was 2 days ago.</p>
<p>Communicating about the scope of work is just as important as schedule.  If we find out a piece of a feature is unfeasable or we dropped it due to time pressure, its important to communicate that.  Depending on your team/product, that may mean sharing with people directly, updating documentation, or just making the new behavior clear in an interface.   </p>
<h3>It’s a process</h3>
<p>Nobody starts out their first software engineering job with a fully evolved sense of how to estimate, scope and document their work.  Most have no clue how to think about building a system to be scalable or when to escalate problems to other members of the team.  These are skills learned through hard experience.  Make sure to <a href="https://benmccormick.org/2019/05/18/obvious-things">always be reflecting</a> on what you’re experiencing though.  Experience combined with reflection is a powerful mixture, and eventually will lead to growth.  Good luck!</p>]]></content:encoded>
      <author>ben@benmccormick.org (Ben McCormick)</author>
    </item>
    <item>
      <title><![CDATA[Book Review: Resilient Management]]></title>
      <link>https://benmccormick.org/2019/07/22/book-review-resilient-management</link>
      <guid>https://benmccormick.org/2019/07/22/book-review-resilient-management</guid>
      <pubDate>Mon, 22 Jul 2019 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://abookapart.com/products/resilient-management">Resilient Management</a> by Lara Hogan is a short and useful read for engineering managers who want to think more systematically about how they support their team.  Lara covers concepts like how to connect with a new team, how to encourage growth in your teammates, and how to communicate difficult news.  This is a <em>blog+</em> book: most of the material here has appeared previously in Lara’s blog or newsletter, but for the book it has been cleaned up and organized together in a coherent fashion that makes it greater than the sum of its parts.</p>
<p>If you’ve followed my <a href="https://benmccormick.org/subscribe">newsletter</a> for a while, you’ll have seen me link to Lara’s work on a regular basis.  Lara’s strength as a teacher is building meaningful exercises for thinking through abstract topics, and that plays out here.  Almost every piece of advice and insight comes with a suggestion on how to start implementing it, or an exercise to help you think deeper about yourself or your situation.  I’ve found her <a href="https://larahogan.me/blog/leadership-style-colors/">leadership colors</a> and her <a href="https://larahogan.me/blog/team-introspection/">MadLibs worksheet for leadership philosophy</a> particularly helpful for me.</p>
<p>In addition to the helpful exercises, the highlights of the book for me were Lara’s look at the BICEPS model for understanding people’s needs at work, the way she structured her book around a groups evolution over time, and the chapter on communication plans.  I’ve made notes to reference each of those areas the next time I hit a relevant situation.</p>
<p>Overall I’d recommend this book to pretty much any early-career engineering manager.  If you’re not already familiar with Lara’s work, there should be some fantastic new ideas for you in here.  If you have followed it, I recommend buying out of appreciation, and to get the concepts bundled in a nice cleanly organized packages.  These are ideas worth paying for.</p>
<p>Resilient Management is available from <a href="https://abookapart.com/products/resilient-management">A Book Apart</a></p>]]></content:encoded>
      <author>ben@benmccormick.org (Ben McCormick)</author>
    </item>
    <item>
      <title><![CDATA[Avoiding Derived State In React]]></title>
      <link>https://benmccormick.org/2019/06/24/derived-state</link>
      <guid>https://benmccormick.org/2019/06/24/derived-state</guid>
      <pubDate>Mon, 24 Jun 2019 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>A lot of advice in the React community is focused around avoiding explicitly storing “derived state” of some type or another.  Some examples of this type of “derived state” that the community warns against:</p>
<h4>Storing data that is directly derived from another piece of data in redux</h4>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> reducer <span class="token operator">=</span> <span class="token function">createReducer</span><span class="token punctuation">(</span>initialState<span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token function-variable function">ADD_USER</span><span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token parameter">state<span class="token punctuation">,</span> action</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    state<span class="token punctuation">.</span>users <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>state<span class="token punctuation">.</span>users<span class="token punctuation">,</span> action<span class="token punctuation">.</span>user<span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token comment">// numUsers is derived state: it will always be tied to users</span>
    state<span class="token punctuation">.</span>numUsers <span class="token operator">=</span> state<span class="token punctuation">.</span>users<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></div>
<h4>Storing state that is directly derived from a prop in a component</h4>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">Widget</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token comment">// the hasError state is derived from the error prop</span>
    <span class="token keyword">let</span> <span class="token punctuation">[</span>hasError<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token operator">!</span>props<span class="token punctuation">.</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//... continued ...</span>
<span class="token punctuation">}</span></code></pre></div>
<h4>Storing state that is directly derived from another piece of state</h4>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">NameForm</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span>
    <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{</span>
            firstName<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
            lastName<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
            fullName<span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// because fullName is directly associated with firstName and lastName, we have to update it</span>
    <span class="token comment">// any time they are updated</span>
    <span class="token function">updateFirstName</span><span class="token punctuation">(</span><span class="token parameter">newFirstName</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token parameter">state</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
            <span class="token operator">...</span>state<span class="token punctuation">,</span>
            firstName<span class="token punctuation">:</span> newFirstName<span class="token punctuation">,</span>
            fullName<span class="token punctuation">:</span> newFirstName <span class="token operator">+</span> <span class="token string">' '</span> <span class="token operator">+</span> state<span class="token punctuation">.</span>lastName<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    <span class="token function">updateLastName</span><span class="token punctuation">(</span><span class="token parameter">newLastName</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token parameter">state</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
            <span class="token operator">...</span>state<span class="token punctuation">,</span>
            lastName<span class="token punctuation">:</span> newLastName<span class="token punctuation">,</span>
            fullName<span class="token punctuation">:</span> state<span class="token punctuation">.</span>firstName <span class="token operator">+</span> <span class="token string">' '</span> <span class="token operator">+</span> newLastName<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// ... continued ....</span>
<span class="token punctuation">}</span></code></pre></div>
<p>These examples are all based on real-world code I’ve seen.  And they all were in code that <em>worked</em>, the program executed as expected.  But they’re still problematic.  This type of derived state is error-prone; when new code is written to update the state, each new programmer touching the code has to understand the relationship, or the whole thing can get out of sync.  When state is coming from props, like the error example above, you have to make sure that the state gets updated properly when the props change. And when the state gets out of sync, it is possible to end up in strange states where a programmer’s expectations are violated.  A program shows a blank state saying no users have been added, even though one has already been created. A form is expecting to have an error, but the error text is empty or set to a default value.  Or a site has 2 different names for an individual that show up differently in separate parts of the interface.</p>
<p>This type of problem isn’t a new thing in Computer Science.  When programmers do it by accident they usually call it a <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY violation</a>.  When they do it intentionally they call it caching.  And when they do it intentionally but screw things up, they <a href="https://twitter.com/secretGeek/status/7269997868">make jokes about off by one errors</a>.  Fortunately, that means that the tradeoffs are pretty well understood here.  So how do we handle situations where it looks like derived state may be necessary?</p>
<h4>Just Derive State At Render Time</h4>
<p>For many many things, including the 3 examples above, if you need information at render time that can be derived from other pieces of state, it’s totally fine to just calculate it at render time.  For the first name example above, you can just include a <code class="language-text">let fullName = this.state.firstName + &#39; &#39; + this.state.lastName;</code> line at the top of your render function and move on<sup id="fnref-1"><a href="#fn-1" class="footnote-ref">1</a></sup>. Storing derived information is unnecessary and harmful when calculating it at runtime adds minimal performance overhead or repetition.</p>
<h4>Memoization</h4>
<p>But Ben, my component is slow now!</p>
<p>…are you sure it’s actually slow?  Have you tested it?  Have you proven that the derived state calculation is actually a meaningful part of this?</p>
<p>Deriving state can be slow when you have to do complicated calculations or reformatting of data.  This is still not usually a problem, but if you’re in a performance sensitive area of code and have proven it to be a problem, you can start considering caching solutions. You still don’t want to store your cached values in state or your redux stores though.  Instead, you want to use a computed value that is recalculated when its inputs change.  The exact code will depend on your state management strategy, but some examples out there include</p>
<ul>
<li><a href="https://github.com/reduxjs/reselect">Reselect for Redux</a></li>
<li><a href="https://mobx.js.org/refguide/computed-decorator.html">Computeds in MobX</a></li>
<li><a href="https://reactjs.org/docs/hooks-reference.html#usememo">useMemo in React Components</a></li>
</ul>
<p>All of these methods use <em>memoization</em>, a type of caching where arguments are passed to a function, and if the function has been called with those arguments before, it returns the previous result rather than recomputing.  If for instance we had a component and wanted to get the names of all <code class="language-text">users</code> with the current <code class="language-text">type</code> based on props, and we knew that <code class="language-text">users</code> was sometimes quite large, making the calculations slow, and we expected the component to re-render often for some reason or another we might write code like this:</p>
<div class="gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">UsersList</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>users<span class="token punctuation">,</span> type<span class="token punctuation">,</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>

    <span class="token keyword">let</span> userNames <span class="token operator">=</span> <span class="token function">useMemo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> users<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">user</span> <span class="token operator">=></span> user<span class="token punctuation">.</span>type <span class="token operator">===</span> type<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>users<span class="token punctuation">,</span> type<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// ... continued ...</span>
<span class="token punctuation">}</span></code></pre></div>
<p>Now userNames will automatically be recalculated only when users or type changes<sup id="fnref-2"><a href="#fn-2" class="footnote-ref">2</a></sup>.  The MobX and Redux solutions work similarly.  Memoization isn’t a performance silver bullet: at some point, you might have to look at how you can make your calculations less expensive or take them off of the rendering path completely.  But for most simple data transformation tasks, deriving state at render time and using memoization to keep it performant where needed should help you tame any derived state problems you encounter.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn-1">
<p>But you should probably read about all the ways that <a href="https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/">names can be more complicated than you think</a></p>
<a href="#fnref-1" class="footnote-backref">↩</a>
</li>
<li id="fn-2">
<p>Note that useMemo (and most memoization solutions generally) doesn’t guarantee the function will never run more than once.  Most solutions have a limited number of results they will store, so if the inputs change often, the result might get recalculated.</p>
<a href="#fnref-2" class="footnote-backref">↩</a>
</li>
</ol>
</div>]]></content:encoded>
      <author>ben@benmccormick.org (Ben McCormick)</author>
    </item>
    <item>
      <title><![CDATA[Lessons From Managing A Distributed Team]]></title>
      <link>https://benmccormick.org/2019/06/24/managing-a-distributed-team</link>
      <guid>https://benmccormick.org/2019/06/24/managing-a-distributed-team</guid>
      <pubDate>Mon, 17 Jun 2019 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Working with people over the internet is different from meeting in an office five days a week.  This isn’t a moral statement.  I’ve done and enjoyed both.  Working with a distributed team requires a different set of skills, especially when you’re a leader.  Today I want to share the most helpful lessons I’ve learned over the last year managing a distributed team.</p>
<h4>Evaluate process and outcomes, not inputs</h4>
<p>Focusing on output` is great advice for any team, but it’s easier and more important when managing remote teams.  When you’re not in the office with people, you won’t see when they start in the morning or finish at night.  You won’t be able to tell if they’re taking long coffee breaks or checking Amazon between tasks.  You’ll have to evaluate them on their output and on the methods they use to get work done.</p>
<p>Evaluating on outputs is tricky for tech work in the short term.  It’s often hard to tell how hard a specific task should have been.  But over the long run, you’ll need to find ways to see if developers are meeting their goals, and focus on that over the exact times they did work.  And this is good, because that is actually what matters.</p>
<p>Output is a lagging indicator though.  In the short term, what you can evaluate if “butts in seats” isn’t an option.  I recommend process: is work being documented, are tests being written and are code reviews being done in a timely manner?  The nice thing about this is that you can check these things in low touch ways; by reviewing your issue tracking and version control systems rather than having status meetings or sending distracting slack messages.  This idea comes up in <a href="https://amzn.to/2XBg1iv">Camille Fournier’s book The Manager’s Path</a>, where she argues persuasively for always doing your information gathering in ways that don’t disrupt your team first.</p>
<h4>1-1s are extra important</h4>
<p>Let’s say Sarah has some lingering concerns about her current project that she’s not yet ready to raise to the full group.  When I work in the same office with Sarah, she can drop by my desk anytime to talk through a small issue.  When we’re working remotely, that may not feel as comfortable for a variety of reasons.  Good 1-1s provide space for the little things to come out.</p>
<h4>When you get in-person time, focus on the relationship</h4>
<p>Currently I get together with my team (and my manager) about once a quarter.  Initially my instinct was to save the “big work stuff” for that time.  And I still try to get a few big conversations in each time, mostly around career development.  But the most value from these visits has come in the gaps, when I go out to lunch with my team and chat, or we get together with a larger group after work.  Time spent together builds trust, and that trust lingers and pays off when you’re back on the other side of the internet the next week.</p>
<h4>Async communication is great.  Don’t neglect “face to face” time.</h4>
<p>“Embrace async communication” is common remote work advice.  When you get stuff done through email/slack/Github/Invision/etc you have fewer meetings and more flow time for your team.  Which is great!  My team takes advantage of “async” tools every day.  But I also try to be intentional about working in “face to face” time through Zoom.  For my team that’s a daily standup and weekly 1-1s, but it could be different for another team’s process.  The key is to not <em>only</em> rely on writing.  Writing is an amazing way to communicate, but it will always lack the context of the human face.  For now I’m aiming for a mix of mostly async with regular “internet face to face”, and occasional “in person”.</p>
<p>Make sure to personalize your communication as well.  If Jerry tends to miss all nuance when you communicate in text, try to spend more time talking over zoom to make sure you’re communicating.  On the other hand if Jennifer has a tendency to lose track of what you’re asking her to do, you may want to give instructions through a text medium, where you can use it for accountability later.</p>
<h4>Hire for remote success</h4>
<p>Not everyone is going to thrive in a remote role.  Most companies hiring remote recognize this and try to filter for it in some form. A lot of companies’ response here is to “only hire senior”.  Which is probably a workable heuristic in some ways.  Developers that have a proven track record of success probably have built up some habits that will help them succeed in remote work even if they aren’t naturally inclined to it.  But hiring only senior folks is expensive, and makes things like diversity and career growth paths harder.</p>
<p>I haven’t done this enough to draw any hard conclusions on remote hiring yet.  But the qualities I want to evaluate for are independence, technological comfort, writing skills, and a history of taking the initiative to seize opportunities (in whatever domain).  Obviously that’s in addition to normal hiring criteria.</p>
<h4>Tools and Process matter</h4>
<p>The worst way to work remote is to not commit to it.  Commitment means aligning your process toward remote work.  Some lessons here.</p>
<p><strong>First, Hybrid meetings are harmful to your team</strong>.  There are 3 ways to do meetings: in person, remote, or hybrid.  An in person meeting involves putting a number of humans in a small room for an hour and letting them talk through an issue.  A remote meeting connects various people from the comforts of whatever work venue they’ve chosen, and discussion ensues over the internet.  In a hybrid meeting, some people are in the room, and some are connecting remotely.  Hybrid meetings are hell for the remote folks.  Usually they can’t hear at least one person well.  They can’t match faces to voices, lose context of what is happening in the room, and are sometimes just plain ignored by the folks in the room.</p>
<p>I really didn’t understand how bad this was until I did it myself a few times.  If you’re a leader who uses or tolerates hybrid meetings, I highly recommend trying to call into them remotely a few times.  As the boss you’ll get a slightly different experience, but ask yourself: are you a first class meeting participant when you’re calling in remote?  If not, is it acceptable to you to treat your remote workers as second class participants?</p>
<p><strong>Second, Use good tools</strong>.  Bad collaboration software is a drag if you’re working with people in person.  It’s a killer for remote teams.  Use software that lets you communicate in timely and useful ways, keep your project critical information organized, and lets your team focus on getting stuff done.  There are hundreds of good tools out there these days, so there’s no excuse for using bad ones.  My recommendations, which are not particularly controversial and also not the only good options: use Zoom for video chat, Slack for messaging, Bitbucket, GitHub, or Gitlab for Version Control, Trello or Jira<sup id="fnref-2"><a href="#fn-2" class="footnote-ref">2</a></sup> for task tracking depending on the size of your team, and Google Drive for keeping documents and documentation together<sup id="fnref-3"><a href="#fn-3" class="footnote-ref">3</a></sup>.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn-2">
<p>I… don’t love Jira.  But Trello doesn’t scale forever, and I haven’t seen anything significantly better than Jira for large teams.</p>
<a href="#fnref-2" class="footnote-backref">↩</a>
</li>
<li id="fn-3">
<p>My team doesn’t actually use Google Docs for documentation, we use Confluence.  Which is… worse than Jira.  So this is more of a “don’t be miserable like me” recommendation than one based on experience.  I’d be curious to hear if anyone has a documentation/wiki tool that they love.</p>
<a href="#fnref-3" class="footnote-backref">↩</a>
</li>
</ol>
</div>]]></content:encoded>
      <author>ben@benmccormick.org (Ben McCormick)</author>
    </item>
    <item>
      <title><![CDATA[Book Review: The Manager's Path]]></title>
      <link>https://benmccormick.org/2019/06/12/book-review-the-managers-path</link>
      <guid>https://benmccormick.org/2019/06/12/book-review-the-managers-path</guid>
      <pubDate>Wed, 12 Jun 2019 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Titles in the software engineering world are strange.  Without much work, it’s easy to find <em>Senior Engineers</em> with 2 years of professional experience, <em>junior developer</em> job descriptions requesting 5 years of experience, <em>tech lead</em> roles focused purely on technology, <em>tech lead</em> roles where the lead is managing a team, and who can tell the difference between a <em>CTO</em> and a <em>VP of Engineering</em> anyway?  This results in weird title shifts when developers switch jobs, odd or unfair salary distributions, and a world where it is very difficult to understand what a career path looks like in this industry.</p>
<p>Camille Fournier’s book <a href="https://amzn.to/2F2jG1p">The Manager’s Path</a> steps into this breach by laying out a clear look at an engineering management-focused career path. The book runs through a series of roles: <em>Mentor</em> to <em>Tech Lead</em> to <em>Manager</em> to <em>Manager of Managers</em> all the way up to <em>Executive</em>. For each role she describes what the job is,  walks through what type of challenges you might face in the role after a promotion, and offers practical advice on overcoming those challenges.</p>
<p>I found it to be an extremely engaging read, and the best description of what it actually looks like to advance in technical leadership roles I’ve ever read.  Because she focuses on skills and responsibilities more than titles, it’s possible to apply her advice across large and small companies, even those with wonky title structures.  It helped me think about what skills I need to be building in my career, and gave me a glimpse of what next steps look like.</p>
<p>The focus on common challenges and how to face them was also helpful, though whole books could (and have) been written on those challenges and how to face them at each level.  The Manager’s Path serves as a good starting point here, identifying the challenges and giving good solid general advice for facing them.  For those new to a role it could help them identify where they’re weak or uncomfortable, and serve as a starting point to a deeper dive into those areas.</p>
<p>As I read the book, I immediately thought of 4 or 5 people at various points in their career I knew who could benefit greatly from reading this book.  If you’re working in the software world and think that you long term are interested in advancing in your career beyond your current role, there will probably be interesting tidbits in here for you.  Even those who are sure they <strong>don’t</strong> want to be in management could benefit from understanding the perspectives of what engineering managers actually <em>do</em>.  The book is also structured so that the first few chapters are highly relevant for both technical and manager track developers; tech lead is an important role on both tracks.  If you fall into one of those buckets, I highly recommend <a href="https://amzn.to/2F2jG1p">The Manager’s Path</a>.</p>]]></content:encoded>
      <author>ben@benmccormick.org (Ben McCormick)</author>
    </item>
    <item>
      <title><![CDATA[Thinking About Values]]></title>
      <link>https://benmccormick.org/2019/06/03/thinking-values</link>
      <guid>https://benmccormick.org/2019/06/03/thinking-values</guid>
      <pubDate>Mon, 03 Jun 2019 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>As a way to help myself grow in my first year as a manager, I’ve been working through <a href="https://rework.withgoogle.com/guides/managers-develop-and-support-managers/steps/review-googles-new-manager-training/">Google’s New Manager Training</a> which they have generously published online.  One exercise that stood out to me was a “values selection” process, where they encourage managers to select a ranked list of 5-10 words that resonate with them as values from a list of around 400 “values words”.</p>
<p><a
    class="gatsby-resp-image-link"
    href="/static/f585fe7fa02d9e97dc89883f7e623db6/67e88/values-list.png"
    style="display: block"
    target="_blank"
    rel="noopener"
  >
    <span
    class="gatsby-resp-image-wrapper"
    style="position: relative; display: block;  max-width: 570px; margin-left: auto; margin-right: auto;"
  >
    <span
      class="gatsby-resp-image-background-image"
      style="padding-bottom: 96.14093959731544%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAACXBIWXMAAAsSAAALEgHS3X78AAAB10lEQVQ4y2WUh47DMAxD8/8/2JnupnvvqcMzQJ3iBggCEzIlUVSK7/dr1+vVjsej3e934wE7nU52uVxMD9j5fLbP5/OD8dVTEFBVlU0mE3s8HgkEG41Gtlwua5en06mt12t7v98eNx6Pbbfb2e12S+dECBnB+/0+gVwmcLFYOKHieNWJsMFgkDpMFXK53+/bbDbzzGC9Xs+Gw+FP1a1Wy1arlWOQdbtdez6f/y2XZZkqQksRttttm8/nfublIslfr5cTkhgZFOeElB4rJDOYBCcOWQ6HQ00G4sB1t5BeqkaEtIeGIuTLmanmg4pxRRQ7XuacJ8ENDC5WSDG0LDt5hbSNTTRlWmEoEltJqBBMLXJPbnANIURwGVnaMPloESVFR03/h1B6YQe1A0Z12+3WTSt7yTLRXrUpSxuCMSeZsQVJOMsy0poE0UpgUZpESGuQQsAOQwoWd1mE4LFCBkeVSuQVooMmJYvI6CKMU1aFYOgtO7mGgHEDwMgejQ1GhfHvAoZcGpLvcr5mYPlWoFWz2azpiEMajUaq1I1Nlk6nY5vNprZ6bEG+ZsRCiA/lhlrLEhthpY8w7CAdIaAacAanTvL9LrT0+e+LFjBx/JkShzT6SyuOBLr3BwgCtgPfjUqrAAAAAElFTkSuQmCC'); background-size: cover; display: block;"
    ></span>
    <img
        class="gatsby-resp-image-image"
        style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;"
        alt="A list of 400 values words like accountability, accuracy, achievement, altruism and more"
        title=""
        src="/static/f585fe7fa02d9e97dc89883f7e623db6/a9e6e/values-list.png"
        srcset="/static/f585fe7fa02d9e97dc89883f7e623db6/40f08/values-list.png 143w,
/static/f585fe7fa02d9e97dc89883f7e623db6/d4502/values-list.png 285w,
/static/f585fe7fa02d9e97dc89883f7e623db6/a9e6e/values-list.png 570w,
/static/f585fe7fa02d9e97dc89883f7e623db6/67e88/values-list.png 596w"
        sizes="(max-width: 570px) 100vw, 570px"
      />
  </span>
  </a></p>
<p>Choosing values is an odd process, because you’re choosing between “goods”.  When I first went through this sheet, I circled over 40 words as values that “resonated” with me.  They’re things that I value and strive for, or wish that I was more like.  Deciding between adventurousness and cowardice is not a “values decision”. A real values decision means that you’re trying to decide whether good traits like adventurousness, belonging, or clear-mindedness are more important to you.</p>
<p>Management often forces you to choose between goods: Will we ship quicker? Aim for higher quality? How do those choices impact work/life balance for our teams?. It’s hard to know if we’re making good choices, because the results routinely lack clarity.  Indicators lag, causation is fuzzy, and we don’t get to compare to a control group.  Values can be guideposts through ambiguity.  I’ve seen the power of this at a company level in my current gig, where having a set of values that are kept in the spotlight often allows us to weaponize them as decision making tools <sup id="fnref-1"><a href="#fn-1" class="footnote-ref">1</a></sup>.</p>
<p>Going through the list, I eventually cut things down to 20, 12, 10 and then 8.  That still feels like a lot to me, but for each of the 8 I can easily cite work situations I’ve faced in the past month where my response came directly out that value.  In the end I ended up with <em>Integrity</em>, <em>Thankfulness</em>, <em>Community</em>, <em>Prudence</em> (in the <a href="https://en.wikipedia.org/wiki/Prudence">classical sense</a>), <em>Generosity</em>, <em>Continual Improvement</em>, <em>Accountability</em>, <em>Justice</em>.  I find that these are easy to connect to my everyday work when I write them out as more detailed sentences though.</p>
<ol>
<li>Act with <em>integrity</em>.</li>
<li>Live with <em>thankfulness</em> for what I’ve been blessed with.</li>
<li>I want to work and live life in <em>community</em>.</li>
<li>Make decisions based on a rational analysis of reality, not feelings and first impressions (<em>Prudence</em>).</li>
<li>Don’t save it all for myself. Leave margin and be <em>generous</em>.</li>
<li><em>Continual Improvement</em> + Goodism are a powerful combo<sup id="fnref-2"><a href="#fn-2" class="footnote-ref">2</a></sup>.</li>
<li>Be <em>accountable</em> for my responsibilities and hold others to the same.</li>
<li>Actively work for <em>justice</em></li>
</ol>
<p>I’ve published them <a href="/my-values">here</a> with a bit more detail.</p>
<p>Those are “guideposts” that I can easily quote to myself or post up somewhere, but they still have enough substance to say something meaningful when I’m considering how to handle a low-performing employee, organizational changes, or personal career decisions. I’ve already seen these values bring a clarity to my thinking about tough things in a short period of time.  If you’re interested, I highly recommend checking out <a href="https://rework.withgoogle.com/guides/managers-develop-and-support-managers/steps/review-googles-new-manager-training/">Google’s training</a>.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn-1">
<p>I’ve also seen how quickly this becomes useless when those values are not universally embraced or enforced.</p>
<a href="#fnref-1" class="footnote-backref">↩</a>
</li>
<li id="fn-2">
<p>Probably a separate post, but <em>goodism</em> has always been my response when asked if I’m a perfectionist: “I’m a goodist.  I care about doing work that is good and meets the needed standards, but tend to move to the next challenge when I pass that bar and hit diminishing returns”.</p>
<a href="#fnref-2" class="footnote-backref">↩</a>
</li>
</ol>
</div>]]></content:encoded>
      <author>ben@benmccormick.org (Ben McCormick)</author>
    </item>
    <item>
      <title><![CDATA[Herding Lions]]></title>
      <link>https://benmccormick.org/2019/05/27/herding-lions</link>
      <guid>https://benmccormick.org/2019/05/27/herding-lions</guid>
      <pubDate>Mon, 27 May 2019 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>I used to find myself using the term “herding cats” a lot when confronting inertia, disorganization or ambiguity in work situations.  <a href="https://www.urbandictionary.com/define.php?term=herding%20cats">Urban Dictionary</a> actually endorses this:</p>
<blockquote>
<p>The phrase herding cats comes from the common saying that something involving coordination of many different groups or people is as difficult as herding cats. One of the commonly encountered uses of the term in technical fields is the phrase “Managing programmers is like herding cats” or “Managing engineers is like herding cats”. In education it would be “Managing students is like herding cats”.</p>
</blockquote>
<p>The phrase correctly captures the difficulty of getting a group of programmers (or even worse <em>teams of programmers</em>) on the same page.  But there’s an inherent arrogance to it.  The implication is that the herder is the adult in the room and everyone else’s pointless individualism is getting in the way.</p>
<p>There are days that I think I could fix everything if I could just get the *&#x26;$% cats to move in the right direction.  In those situations  I’ve started telling myself that what I’m actually doing is herding <strong>lions</strong>.  How do you herd a group of lions?  I have no idea.  But I know that if you don’t start with a healthy respect for the lion’s capabilities and agenda, it won’t end well for you.</p>
<p>When you treat people like lions, it’s an opportunity to stop and figure out <em>why</em> they’re not just getting on board with your <em>obvious</em> plan.  It’s an opportunity to learn, to find new ways to motivate people, and maybe even to empower somebody who had been viewing themselves as more of a kitten.  Ultimately the best teams flourish where people can <a href="https://rework.withgoogle.com/blog/five-keys-to-a-successful-google-team/">be strong contributors, take risks and do work they find meaningful</a>.  They’re teams of lions.</p>]]></content:encoded>
      <author>ben@benmccormick.org (Ben McCormick)</author>
    </item>
    <item>
      <title><![CDATA[Obvious Things]]></title>
      <link>https://benmccormick.org/2019/05/18/obvious-things</link>
      <guid>https://benmccormick.org/2019/05/18/obvious-things</guid>
      <pubDate>Sat, 18 May 2019 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>I saw a tweet thread a few weeks ago that made me think:</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">There’s a bit of a meme in some parts that there is value in saying, out loud, “I realize that I am surprised.” For similar reasons, I often subvocalize “I believe I now understand the type of situation the ‘trivial’ advice was preparing me for.” <a href="https://t.co/JzdYmSvJWH">https://t.co/JzdYmSvJWH</a></p>&mdash; Patrick McKenzie (@patio11) <a href="https://twitter.com/patio11/status/1115751939210223616?ref_src=twsrc%5Etfw">April 9, 2019</a></blockquote>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">And then you repeat it to someone and they say “lol that is obvious” and you wonder if you know the advice well enough yet to correct them on how not obvious it is going to be for their next 10 years.</p>&mdash; Patrick McKenzie (@patio11) <a href="https://twitter.com/patio11/status/1115752453910061056?ref_src=twsrc%5Etfw">April 9, 2019</a></blockquote>
<p>I realized that I’ve encountered plenty of pieces of wisdom in my software career that have this property; I see them as clear and obvious when put in the abstract, but only learn to actually apply them by repeatedly failing to do so.  This is what people talk about when they say something is “hard earned experience” I guess.</p>
<p>Here are some examples from my career:</p>
<ol>
<li><strong>In the long run, rate of improvement (or regression) matters more than current level</strong> - This has applications in hiring, code quality, and finding/staying in a job.  But it’s often easier to observe how good something is now than to see how its changing, and I often fail to properly estimate what a trend means for a situation 1-3 years down the road.  It’s also easy to mis-apply this principle when you for get about the “long run” part.  A new employee with tons of potential won’t help you when you need an experienced hand <em>now</em> and fixing technical debt can easily cost you your ability to hit a quarterly objective.  Knowing how to balance these long and short term goals is something I still struggle with all the time.</li>
<li><strong>Rewriting from scratch is (almost) never worth it</strong> - <a href="https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/">Joel Spoelsky</a> wrote about this way back in 2000 and I remember reading that article nearly a decade ago and nodding along.  I seem to have infinite capacity to convince myself that my current situation fits in those parentheses though.  In my career this has mostly been a problem where I’m able to more accurately forecast the pain that would ensue from fixing what exists (because that code exists and is easier to work with), while I appear to systematically underestimate the pain of building the new thing (because the internet told me it would be great, and the code doesn’t exist for me to nitpick yet).</li>
<li><strong>Always consider multiple options</strong> - Pretty much any decision (technical or otherwise) benefits from having multiple contenders.  This seems obvious.  But I have often let myself fall into situations where I’m choosing between just 2 options, or really just choosing whether or not to do 1 thing.  This has applications in technology choices, job choices, responding to another person’s provocations, and more.  I intuitively know that more options are good, and I constantly miss opportunities to add options.</li>
</ol>
<p>So how do we improve on these situations where we fail to apply <em>obvious</em> wisdom?  I’ve been learning a few things lately.</p>
<ol>
<li><strong>Always review what you’ve done on a regular basis</strong> - Do weekly reviews about how your week went.  Do quarterly reviews with yourself about how your job is going.  When you make big decisions, make sure to find a time to check back in later and evaluate how it went.  We make better decisions when we take the time to measure our results</li>
<li><strong>Note Missed Opportunities</strong> - When you do those reviews, make sure to pay attention to when you missed an opportunity to apply something you <em>knew</em>.  Sometimes we make mistakes because we just didn’t know something.  It’s more common though that we didn’t properly apply our own principles and knowledge.</li>
<li><strong>Identify Cues</strong> - Identify the thing that you know you’re going to have to handle different next time.  Maybe you say “if I’m looking for a job, I should consider at least 4 or 5 different companies and not focus in on just one”, or if I’m asked to fix a legacy codebase, I will spend at least 3 months trying to improve it before considering a re-write,and I’ll look for real world comparisons to base a rewrite estimate on”.  Whatever it is for you, when you can identify situations where a specific action should take place, it can help you be better the next time instead of repeating the same old mistakes.</li>
</ol>]]></content:encoded>
      <author>ben@benmccormick.org (Ben McCormick)</author>
    </item>
  </channel>
</rss>
