<?xml version="1.0" encoding="UTF-8"?>
<!--Generated by Site-Server v@build.version@ (http://www.squarespace.com) on Tue, 21 Apr 2026 19:44:29 GMT
--><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://www.rssboard.org/media-rss" version="2.0"><channel><title>Zach Mayer .Net</title><link>http://www.zachmayer.net/</link><lastBuildDate>Fri, 08 Dec 2017 05:40:59 +0000</lastBuildDate><language>en-US</language><generator>Site-Server v@build.version@ (http://www.squarespace.com)</generator><description><![CDATA[]]></description><item><title>Message Decoder</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Fri, 08 Dec 2017 06:08:00 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/12/7/message-decoder</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a2a25eb9140b736108878d3</guid><description><![CDATA[<p>I can't remember where I first heard about this one but I like it because it's almost exactly as simple as it sounds, but if you insist on working through the whole solution it's a great question for junior engineers.</p>























<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>Given a string representing an encoded matrix and a decryption key, write a function to decode the message.<span>”</span>
  </blockquote>
  
  
  
</figure>


  <p>This one requires a bit more explanation. First, our "encoded" string looks like this...</p>
























  
    <pre class="source-code"><span class="cm-string">"I B C A R L A M T A R G C E S T A C M H O W A A"</span></pre>
  




  <p>Now, imagine this string as a matrix the length of which matches the given integer key, say 3, and the message is in the highlighted characters below...</p>
























  
    <pre class="source-code">[
  [<span class="cm-string">'-I- '</span>, <span class="cm-string">'B'</span>,  <span class="cm-string">'C'</span>,  <span class="cm-string">'A'</span>, <span class="cm-string">'-R-'</span>, <span class="cm-string">'L'</span>,  <span class="cm-string">'A'</span>,  <span class="cm-string">'M'</span>],
  [ <span class="cm-string">'T'</span>,  <span class="cm-string">'-A-'</span>, <span class="cm-string">'R'</span>, <span class="cm-string">'-G-'</span>, <span class="cm-string">'C'</span>, <span class="cm-string">'-E-'</span>, <span class="cm-string">'S'</span>, <span class="cm-string">'-T-'</span>],
  [ <span class="cm-string">'A'</span>,   <span class="cm-string">'C'</span>, <span class="cm-string">'-M-'</span>, <span class="cm-string">'H'</span>,  <span class="cm-string">'O'</span>,  <span class="cm-string">'W'</span>, <span class="cm-string">'-A-'</span>, <span class="cm-string">'A'</span>]
]</pre>
  




  <p>Can you see the pattern? Starting from the top left, move down and right, then up and right, and so on until you reach the end of the matrix.</p><p>Our task is to first munge the input into the desired shape, and then scrape through the matrix for the message.</p><p>Here's the code that does just that, with the slight twist that I chose to arrange the matrix by column,&nbsp;but either way the core is the same.</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/Message-Decoder?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="800px" ></iframe>
  




  <p>Fun fact: the message in the code above can also be decoded with a key of 4 and a different message :-p</p>]]></description></item><item><title>Make the Largest Number</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Tue, 05 Dec 2017 23:20:54 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/12/4/make-the-largest-number</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a2619d5652deaa85498ff3f</guid><description><![CDATA[<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>Write a function that given a list of non negative integers, arranges them such that they form the largest possible number. For example, given [50, 2, 1, 9], the largest formed number is 95021.<span>”</span>
  </blockquote>
  <figcaption class="source">&mdash; Santiago L. Valdarrama</figcaption>
  
  
</figure>


  <p>This one comes from an excellent blog by Mr. Valdarrama and <a target="_blank" href="http://www.shiftedup.com/2015/05/07/five-programming-problems-every-software-engineer-should-be-able-to-solve-in-less-than-1-hour">his apparently controversial post</a> from a couple years ago.</p><p>Readers of the blog apparently came up with a few close-but-not-quite solutions, but all of them involve building a custom comparator for sorting the input array and then joining the array into a numerical string. Discerning what goes into the guts of the comparator is certainly a challenge, which is why I've never asked this particular question in an interview, but it's worth seeing how this problem can be solved I think, given a few different inputs.</p><p>First let's consider the initial input, [50, 2, 1, 9]</p><p>Looking at that sample we might think that doing a straight numerical comparison by iterating through each digit in the comparator's left and right arguments might work, and for this input it certainly does.</p><p>Here's a solution with numerical comparison by padding numbers with fewer digits with the previous digit (so 5 v 56 becomes 55 v 56).</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/Make-Largest-Numeric?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="700px" ></iframe>
  




  <p>That solution fails for a test input like &nbsp;[420, 42, 423] which should generate 42423420, but instead comes up with 42342420.</p><p>The answer it turns out is much simpler to write but more nuanced. Rather than comparing numbers directly to each other, if we compare the difference between the parsed strings made by combining the numbers lexically and determining which combination is larger we can create a simple rule for our comparator to test that works for all cases.</p><p>Check it out.</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/Make-Largest-Lexical?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="600px" ></iframe>
  




  <p>This is almost exactly the same as the standard <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort">comparator for integers</a>&nbsp;except we're simply testing combinations of strings to see which pair makes the larger number, then bubbling the winner to the front of the array each step. At the end, we'll always end up with the largest possible number! Also we could reverse the order of the parseInt clauses to find the smallest possible number, which is pretty cool!</p>]]></description></item><item><title>Flatten an Array</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Fri, 01 Dec 2017 23:16:16 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/12/1/flatten-an-array</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a21dd2a652dea21c5acd18b</guid><description><![CDATA[<p>I'm tired today, so I want to look at an easier problem.</p>























<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>Write a function that accepts an array of arbitrary type, which may contain nested arrays. Return the same array with values in the nested arrays promoted to the top-level parent.<span>”</span>
  </blockquote>
  
  
  
</figure>


  <p>So given an input like this...</p>
























  
    <pre class="source-code">[ <span class="cm-number">1</span>, <span class="cm-number">2</span>, {<span class="cm-string cm-property">'a'</span>:<span class="cm-number">2.5</span>}, <span class="cm-number">3</span>, [<span class="cm-number">4</span>, [<span class="cm-number">5</span>, [<span class="cm-number">6</span>, <span class="cm-number">7</span>], <span class="cm-number">8</span>, [<span class="cm-number">9</span>, <span class="cm-number">0</span>]]] ]</pre>
  




  <p>Turn it into an array like this...</p>
























  
    <pre class="source-code">[ <span class="cm-number">1</span>, <span class="cm-number">2</span>, { <span class="cm-property">a</span>: <span class="cm-number">2.5</span> }, <span class="cm-number">3</span>, <span class="cm-number">4</span>, <span class="cm-number">5</span>, <span class="cm-number">6</span>, <span class="cm-number">7</span>, <span class="cm-number">8</span>, <span class="cm-number">9</span>, <span class="cm-number">0</span> ]</pre>
  




  <p>Someone familiar with the Array.reduce() function might immediately feel like it's a good fit, and they'd be right if each item in the input array was also an array. The problem with reduce for this input is that you can't back-track easily, so your solution will most likely be some form of recursion.</p><p>There's still a simple solution however, and I think it's pretty elegant. Using Array.splice() and a cursor we can decrement whenever we need to flatten an array we can step through the input array iteratively and continuously until even deeply nested arrays are bubbled up to the top level.</p><p>This solution works because <em>Array.splice()</em> takes an arbitrary number of arguments after the first two, and each of those arguments is an item to be cut into the target array. Before the array spread operator (...)&nbsp;we'd need to use <em>Function.apply()</em> and concatenate our nested array with the first two arguments for <em>splice</em>, then apply that array of arguments to splice for the target array. Something like this...</p>
























  
    <pre class="source-code"><span class="cm-variable">Array</span>.<span class="cm-property">prototype</span>.<span class="cm-property">splice</span>.<span class="cm-property">apply</span>(<span class="cm-variable">arr</span>, [<span class="cm-variable">i</span>, <span class="cm-number">1</span>].<span class="cm-property">concat</span>(<span class="cm-variable">arr</span>[<span class="cm-variable">i</span>]));</pre>
  




  <p>With array spreading we can do the same thing with much better readability, as demonstrated:</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/Flatten-Arrays?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="420px" ></iframe>
  




  <p>It should be noted that this solution modified the original array in-place. It's trivial to modify this to be a function on <em>Array.prototype,&nbsp;</em>which would allow for perhaps a prettier syntax like <em>input.flatten()</em></p><p>I prefer the un-prototyped solution personally, if only because "don't mess with common language prototypes" is seared into my brain from long ago.</p>]]></description></item><item><title>Duck Duck Goose</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Thu, 30 Nov 2017 22:42:04 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/11/30/duck-duck-goose</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a2084ee9140b77b548d513c</guid><description><![CDATA[<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>Create a function that predicts the winner of a game of “duck duck goose.”<span>”</span>
  </blockquote>
  
  
  
</figure>


  <p>This is a deceptively simple question, and solving it requires a careful exploration of the rules of the game. It's a really good test of how well your candidate can gather requirements, understand a problem, and execute an effective solution.</p><p>Let's start with the requirements. A game of duck duck goose is played, for our purposes, by progressively eliminating items from a set of "players" until only one is left. The "goose" in our representation of the game will just be an integer representing the number of "skips" taken each round, and the players will be an array of strings. Each round, when a player is eliminated from the game the next round will begin starting with the player just after the removed player.</p><p>It's tempting to reach for a stack or queue-like data-structure here because of that last rule; starting each round where we left off last round. With a queue, as the goose skips around the players we can dequeue and re-enqueue until we reach the appropriate number of skips where we dequeue one last time and start the next round. We finish the game when only one player is left in the queue and return that survivor.</p><p>While the queue solution works, it requires a hefty number of operations since we have to enqueue and dequeue for each skip <em>every single round</em>. Even when we have a small player set, a huge skip count will force that algorithm will to take an excessively long time.</p><p>Fortunately there's an effective way to make the algorithm linear with the player-count instead, and that's by simply recognizing that the eliminated player each round will always be the remaining player-count MOD the skip-count. Once we know that, it becomes obvious that each round is just a math problem, and a concatenation of the end of the array of players (after the eliminated index) with the beginning (before the eliminated index). With this solution we're not bound by the skip count can be arbitrarily large and our only performance variable is the player-count!</p><p>Here's the solution with comments showing the result of each round and the player index to be dropped :)</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/Duck-Duck-Goose?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="600px" ></iframe>]]></description></item><item><title>Rotate a Matrix</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Wed, 29 Nov 2017 23:58:41 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/11/20/rotate-a-matrix</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a130ee224a694588706babb</guid><description><![CDATA[<p>This problem comes from the truly awesome <em><a target="_blank" href="https://www.amazon.com/Cracking-Coding-Interview-Programming-Questions/dp/0984782850">Cracking the Coding Interview</a>:</em></p>























<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>Given an image represented by an NxN matrix… write a method to rotate the [matrix] by 90 degrees. Can you do this in place?<span>”</span>
  </blockquote>
  <figcaption class="source">&mdash; Cracking the Coding Interview</figcaption>
  
  
</figure>


  <p>This one can get a bit brain-bendy, but if we take a step back and look at a simple case first, it might become more clear. If it's still muddy there's an animation and a link to a really great article that visualizes what's going on at the bottom.</p><p>So let's try to rotate the simplest useful matrix we can:&nbsp;a 2x2 matrix of integers. We'll represent the matrix as a 2-D array, and since there are only the four elements we can brute-force the rotation by swapping the appropriate corners.</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/Rotate-Matrix-Simple?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="800px" ></iframe>
  




  <p>This is the meat of each step we'll need to take to rotate a larger matrix.</p><p>The gist of the algorithm we'll need to solve the problem is to rotate the matrix from the outside-in, and from the corners first. If we break the matrix in to concentric "rings" that we rotate independently, it starts to follow that to rotate one layer, we just find the min and max indices, offset by the current step, and swap the corners until we hit the limit (i.e. that length of one side of the current layer).</p><p>I've tried to annotate the code below to try and make it clear what's happening at each step. Without a visual aid it's still kind of hard to follow...</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/Rotate-Matrix?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="800px" ></iframe>
  




  <p>BUT... Here's a handy visual for how the algorithm works! Check out the image credit for an even more in-depth visual break-down of the pinwheel algorithm.</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          <a class="
                sqs-block-image-link
                
          
        
              " href="https://galencorey.wordpress.com/2016/11/18/rotating-a-matrix-with-gifs/" target="_blank"
          >
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1511997796783-5BZHGLEQSLHYMDC3YIDG/flipmatrix.gif" data-image-dimensions="661x372" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1511997796783-5BZHGLEQSLHYMDC3YIDG/flipmatrix.gif?format=1000w" width="661" height="372" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1511997796783-5BZHGLEQSLHYMDC3YIDG/flipmatrix.gif?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1511997796783-5BZHGLEQSLHYMDC3YIDG/flipmatrix.gif?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1511997796783-5BZHGLEQSLHYMDC3YIDG/flipmatrix.gif?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1511997796783-5BZHGLEQSLHYMDC3YIDG/flipmatrix.gif?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1511997796783-5BZHGLEQSLHYMDC3YIDG/flipmatrix.gif?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1511997796783-5BZHGLEQSLHYMDC3YIDG/flipmatrix.gif?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1511997796783-5BZHGLEQSLHYMDC3YIDG/flipmatrix.gif?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          </a>
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>via <a target="_blank" href="https://galencorey.wordpress.com/2016/11/18/rotating-a-matrix-with-gifs/">galencorey.wordpress.com</a></p>
          </figcaption>
        
      
        </figure>]]></description></item><item><title>Spaceless Strings</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Wed, 22 Nov 2017 23:21:04 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/11/20/spaceless-strings</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a1345478165f56f1ace69f4</guid><description><![CDATA[<p>I considered splitting this into three separate posts but decided against it. Today's episode is going to through three iterations on the initial problem, each expanding on the last. So without further ado, here's the first problem...</p>























<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>Build a function that, given a dictionary of words and a string without spaces, capitalization, or punctuation, returns whether the string is a complete sentence.<span>”</span>
  </blockquote>
  
  
  
</figure>


  <p>So given the input: "thisisawesome" (which you can totally search for to find this question and solutions), and a dictionary of words that are contained within it, we'll want to iterate over the characters in the string until we find a word. At that point we'll have split our string into two parts: the left side with a known word, and the right that remains unknown.</p><p>If we use a recursive function to find the first complete word in a given string that returns "true" for a string length 0, we can use it to check the right side of each string split in the recursive stack until we either have nothing on the right, or some leftover characters that can't be parsed into words. When the latter happens we know we can't split the string into a complete sentence and should return false. Below is a solution.</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/Can-Split-String?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="400px" ></iframe>
  




  <p>And that's pretty simple, right? It's probably pretty obvious where our first expansion will be...</p>























<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>Given the same string and dictionary, create a function that returns a possible sentence the string could be split into.<span>”</span>
  </blockquote>
  
  
  
</figure>


  <p>Since we've already solved the first part, this next part isn't too difficult; we just need to keep track of the words on the left as we find them. Doing that with basically the same recursive strategy means we can add a result tracking parameter to the method signature and pass that plus the found word to each subsequent recursive call. The result when we unwind the stack will be a sentence split into the smallest possible words at every step. Check it out below.</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/Get-Split-String?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="400px" ></iframe>
  




  <p>The solution above is almost the same at the first iteration, just with added tracking. Instead of returning "true" though, we return our "result" tracking param. Since we still return false when we fail to split a string, this solution will either return a sentence, or "false".</p><p>Buuuuut "this is a we so me" isn't really the result we'd expect, is it? Time for one last expansion:</p>























<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>Find a way to split the string into all possible complete sentences.<span>”</span>
  </blockquote>
  
  
  
</figure>


  <p>This expansion isn't as bad as it sounds, and after going through the last two iterations it's pretty clear all we need to do is add an additional tracking param to the recursive function to keep an array of solutions from the result parameter.</p><p>The biggest difference is that we'll change up the break-out method for the recursion from a pre-check condition outside the loop, to a terminal check inside the loop. That's just saying that once we find the last word in the string we should push (unshift in the solution below) the sentence into the tracking array. Once we unwind the recursion, the tracking array will have all our possible sentences, and we can simply return it in all cases. Now since we're looking for <em>all</em>&nbsp;solutions, we can return an empty array when we don't find anything. Check it out below:</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/String-Splitter?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="400px" ></iframe>
  




  <p>BAM. Kicked it up a notch. The reason I used "unshift" in the solution above is because the nature of our result tracker means we find the shortest words first, and therefor the sentences we find first have the most possible splits. Using "unshift" for the sentence tracker lets us return the strings with the least splits (and the most compound words) first, and makes it more likely the intended string is near the top of the result set.</p><p>But wait there's more! None of these can do much about a sentence that doesn't split properly besides fall out of the recursion. The last expansion is an exercise for the reader (mostly because I've run out of time). Good luck!</p>























<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>Given that we now have a function that can find all possible complete sentences, modify it to return the “problem characters” for a string that does not split completely. These may appear in the middle of a string like, “thisisxawesome” or the middle of a word like, “thxisisawesome”<span>”</span>
  </blockquote>
  
  
  
</figure>]]></description></item><item><title>LRU Cache</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Tue, 21 Nov 2017 10:50:55 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/11/20/lru-cache</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a130e720d92977e292de9b2</guid><description><![CDATA[<p>I found this question a good long time ago but I've only ever used it once and I'm sorry to say it didn't go well, but that's probably on me.</p>























<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>Implement an LRU cache with get, set, and remove functions that keeps track of key-value-pairs. Bonus points for making each operation O-1 complexity.<span>”</span>
  </blockquote>
  
  
  
</figure>


  <p>It makes a good whiteboard data structures problem for candidates that maybe have stronger back-end skills. An LRU Cache is a data structure that has a set limit on it's content length and culls the "Least Recently Used" item when it exceeds it's capacity. It's tempting to reach for a stack or queue for this one because the idea of keeping an order to the items in the cache by last-accessed (ordinal or time-stamp) will pretty much solve the problem, but keeping the array-like structures ordered is expensive; on the order of O-nlog(n) for every set, get, or delete. Even if you co-implement a map to make accessing items fast, you still have to re-order the set because of the LRU rules.</p><p>An optimal solution is to use a doubly-linked list combined with a map for internal lookups. Each operation required in a DLL (I know, overloading a TLA) is O-1; much better than the stack or queue solution!</p><p>As a bonus follow-up, assuming the white-boarding goes well and we eventually arrive at the DLL solution, it's a fun quick follow-up to ask for a function that can render the queue as an array or object since we are, after all, storing key-value-pairs.</p><p>The code below is a working implementation that eschews some type checking and extra safeties for comprehensibility and includes a "toArray" function on the cache that emits an array of key-value-pairs in order of most to least recently used.</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/LRU-Cache?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="1200px" ></iframe>
  




  <p>You can see why this might make a better whiteboard question. While it's certainly possible for a good candidate to come up with a solution like this in a typical 30-60 minute phone-screen, it's going to leave a lot of dead-air while they physically type it all up. I generally prefer questions with more terse solutions so I get more time to talk about thought process and code-hardening, but I like that this one combines data-structures with real business rules and isn't just "implement a linked list."</p>]]></description></item><item><title>Reverse a String</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Mon, 20 Nov 2017 16:38:57 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/11/20/reverse-a-string</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a1305269140b742d6772ea3</guid><description><![CDATA[<p>A really quick one today since I don't have a whole lot of time.</p><p>Reversing a string is the same as reversing an array. There are a few ways to do it and most are linear algorithms to one degree or another. Where solutions differ is more often not on speed or complexity but on readability. That said, here's the one I like best. It's O-n/2, which makes it nice and linear and it's easy to intuitively understand what's happening from even obfuscated code.</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/ReverseString?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="550px" ></iframe>
  




  <p>This sort of problem in an interview can easily be made part of a larger problem set like finding palindromes, but mostly it's a Fizz-Buzz style smoke test for fundamentals comprehension.</p>]]></description></item><item><title>Merge Sorted Arrays</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Fri, 17 Nov 2017 08:01:00 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/11/16/merge-sorted-arrays</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a0e1597f9619a940bcf2289</guid><description><![CDATA[<p>Today's question is one I like to ask interns because it's a super simple algorithm that tests the candidates knowledge of basic programming concepts, and has some natural expansions in the edge cases and optimization. Those easy expansions help generate a good conversational flow in an interview setting and helps give a sense of the candidate's ability to not only solve the immediate problem, but see how they deal with complications or changing requirements.&nbsp;What this question ultimately drives toward is an implementation of the Array.concat method which handles all the different expansions, plus can merge multiple arrays together.</p>























<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>Given two pre-sorted arrays of uniform type and equal length, merge them into a single sorted array.<span>”</span>
  </blockquote>
  
  
  
</figure>


  <p>Sounds easy enough. Let's assume the following inputs...</p>
























  
    <pre class="source-code"><span class="cm-keyword">const</span> <span class="cm-def">a</span> <span class="cm-operator">=</span> [<span class="cm-number">1</span>, <span class="cm-number">3</span>, <span class="cm-number">5</span>, <span class="cm-number">7</span>, <span class="cm-number">7</span>, <span class="cm-number">8</span>, <span class="cm-number">8</span>, <span class="cm-number">9</span>, <span class="cm-number">9</span>];
<span class="cm-keyword">const</span> <span class="cm-def">b</span> <span class="cm-operator">=</span> [<span class="cm-number">2</span>, <span class="cm-number">4</span>, <span class="cm-number">5</span>, <span class="cm-number">6</span>, <span class="cm-number">7</span>, <span class="cm-number">8</span>, <span class="cm-number">9</span>, <span class="cm-number">10</span>, <span class="cm-number">11</span>];</pre>
  




  <p>It's pretty easy to see what we need to do here: curse over both arrays from left to right, building a new array based on comparing the correct indices as we go. Here's what that looks like</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/Merge2Sorted1?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="400px" ></iframe>
  




  <p>Here the first step is to find the max length of our result so we have a target to terminate the while loop further down. Then we just create two cursors (lastA and lastB) that track the current index of each array to compare in each iteration.</p><p>In the loop we simply compare the value of the each array at the corresponding cursor index and push the winner: in this case, the smaller value. The result is a nice linear algorithm.</p><p>Now for the first expansion:&nbsp;</p>























<figure class=""
>
  <blockquote data-animation-role="quote" data-animation-override>
    <span>“</span>What if the input arrays are unequal length?<span>”</span>
  </blockquote>
  
  
  
</figure>


  <p>The solution above breaks down when you have inputs like this:</p>
























  
    <pre class="source-code"><span class="cm-keyword">const</span> <span class="cm-def">a</span> <span class="cm-operator">=</span> [<span class="cm-number">1</span>, <span class="cm-number">3</span>, <span class="cm-number">5</span>, <span class="cm-number">7</span>, <span class="cm-number">7</span>, <span class="cm-number">8</span>, <span class="cm-number">8</span>, <span class="cm-number">9</span>, <span class="cm-number">9</span>];
<span class="cm-keyword">const</span> <span class="cm-def">b</span> <span class="cm-operator">=</span> [<span class="cm-number">2</span>, <span class="cm-number">4</span>, <span class="cm-number">5</span>, <span class="cm-number">6</span>, <span class="cm-number">7</span>];</pre>
  




  <p>And that's because we're missing bounds checks! We just need to check if our cursor position for either array exceeds the length of it's array and from there we just append the remainder of the larger array to the result. We <em>could </em>alternatively create a new set of three arrays: two of equal length, and one for the remainder of the larger of the two original arrays, but that increases the memory requirements.&nbsp;</p><p>A clever candidate will recognize the opportunity to use Function.Apply() for this. Here's what that looks like:</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/Merge2Sorted2?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="400px" ></iframe>
  




  <p>Pretty easy, right? Being familiar with how to use apply means we don't have to loop over the arrays again, and we can use the array function push to do all our work for us! This has the handy side-effect of also handling the case where one of our arrays is empty since the cursors start at 0, and one of the bounds conditions will pass in that case. By putting the bound checking first in the loop we can break our sooner and prevent dangling undefined's in our result array from the un-bound else statement.</p><p>This is already a little longer than I planned, but the next expansion would be to accommodate different datatypes being mixed and matched. That expansion is a lot more open ended because at that point we have to develop and agree on rules for ordering the mis-matched types. Do they interlace? Do we order types into chunks somehow?</p><p>You could also branch into dealing with unsorted arrays; do you sort as you go? Pre-sort the inputs? Or just toss everything into one big array and sort the result? Implementing the sort itself might be out of scope for a short interview, just because it's a separate algorithm, but if you have time it's definitely worth seeing which sorting scheme the candidate reaches for, and provides an "in" for a discussion about sorting algorithm trade-offs.</p>]]></description></item><item><title>Count the Blocks</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Thu, 16 Nov 2017 08:01:00 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/11/14/count-the-blocks</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a0b601de4966bc2bbac385b</guid><description><![CDATA[<p>Given a 2-dimensional array of values, count the blocks of identical values and return the counts as a map.</p><p>A block is defined as a contiguous selection of cells with identical values along the horizontal and vertical (but not diagonal) axes.</p><p>So, given an input array like this...</p>
























  
    <pre class="source-code">[[<span class="cm-string">'R'</span>, <span class="cm-string">'R'</span>, <span class="cm-string">'B'</span>, <span class="cm-string">'G'</span>],
 [<span class="cm-string">'R'</span>, <span class="cm-string">'B'</span>, <span class="cm-string">'B'</span>, <span class="cm-string">'G'</span>],
 [<span class="cm-string">'B'</span>, <span class="cm-string">'G'</span>, <span class="cm-string">'G'</span>, <span class="cm-string">'G'</span>],
 [<span class="cm-string">'B'</span>, <span class="cm-string">'G'</span>, <span class="cm-string">'G'</span>, <span class="cm-string">'R'</span>]]</pre>
  




  <p>Generate a map of block counts like this...</p>
























  
    <pre class="source-code"><span class="cm-variable">Map</span> { <span class="cm-string">'R'</span> <span class="cm-operator">=&gt;</span> <span class="cm-number">2</span>, <span class="cm-string">'B'</span> <span class="cm-operator">=&gt;</span> <span class="cm-number">2</span>, <span class="cm-string">'G'</span> <span class="cm-operator">=&gt;</span> <span class="cm-number">1</span> }</pre>
  




  <p>Seems easy enough. We'll definitely need to iterate over all the items in the array at least once, and likely several time as we focus on different block types. What we'll need is a breadth first approach, and to make it work we'll need to be able to track which cells we've visited and counted as part of a block.</p><p><strong>Map </strong>is our friend here and we'll need two: one to track the counts of each unique block type, and one to track the visited cells. We could perhaps only do this with one block if we were allowed to either modify the input, or pre-process the input to make the strings into objects with a 'visited' property. Either of those would save us some complexity, but maybe not enough to make a huge difference.</p><p>The basics of the breadth first search are pretty simple. From a given index, (X, Y), we can determine if the value at the index is unique, if the index has been visited, and if the cell at the index has neighbors with the same value (are part of a block). We can then recursively explore in the cardinal directions (up, down, left, and right) looking only for the cells with the same value as our original index, marking 'visited' as we go.</p><p>As we curse over each index in the array building our map of visited indices, the iterations will get faster as we'll (hopefully) need to dive into the recursive search function less and less.</p><p>Let's take a look at a solution...</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/FindBlocks?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="1100px" ></iframe>
  




  <p>Now, since we need to touch every index in the input array at least once, let's start with an assumption that N is the total length of a flattened input array. If we also assume that every index is unique, our direction checks will be made for each index four times regardless of position, plus the check on the index itself.&nbsp;That puts our worst-case complexity at O-5N, or just ON which is pretty good!&nbsp;</p><p>For now, I'm happy with this solution but if you're reading this and you know a better one, let me know!</p>]]></description></item><item><title>Find Anagrams in a List</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Wed, 15 Nov 2017 08:01:00 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/11/15/find-anagrams-in-a-list</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a0b52ea0852294958dcf665</guid><description><![CDATA[<p>The first interview question in the new blog series is pretty simple. Given an array of strings, find which strings are anagrams of each other and group them together. The result will be a two-dimensional array.</p><p>Special Rules:</p><ol dir="ltr"><li>Respect case. 'Abc' is different from 'abc.'</li><li>Remove duplicates. Return values should all be unique.</li></ol><p>So, given the array:</p>
























  
    <pre class="source-code">[<span class="cm-string">'xxy'</span>, <span class="cm-string">'cab'</span>, <span class="cm-string">'bac'</span>, <span class="cm-string">'cab'</span>]</pre>
  




  <p>We should return:</p>
























  
    <pre class="source-code">[[<span class="cm-string">'xxy'</span>], [<span class="cm-string">'cab'</span>, <span class="cm-string">'bac'</span>]]</pre>
  




  <p>Right off the bat, there are two things that should call out to us while we build the <strong>findAnagrams </strong>function.</p><p>First, we want unique values from the input array. That means we can convert the input array to a <strong>Set</strong>, saving a loop and check on the final product.</p><p>Second, since we respect case and we know we're looking for anagrams, we can compare strings that are sorted by their characters without any extra normalization. Since we're sorting the strings and looking for matches from those sorts, the most obvious data structure to use is a <strong>Map</strong>.</p><p>Basically, we'll create a set from our input array, then iterate over the set, sorting each entry's characters and adding the sorted strings as keys to map (where no such key exists) and the original strings as values in the map. The map will then look something like...</p>
























  
    <pre class="source-code">{<span class="cm-string">'xxy'</span>: [<span class="cm-string">'xxy'</span>], <span class="cm-string">'abc'</span>: [<span class="cm-string">'cab'</span>, <span class="cm-string">'bac'</span>]}</pre>
  




  <p>...and we can just convert the map's values to an array.</p><p>Easy-peasy, here's the code :)</p>
























  
    <iframe scrolling="no" allowfullscreen="true" src="https://repl.it/@GenericGuy35/FindAnagrams?lite=true" width="100%" allowtransparency="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals" frameborder="no" height="610px" ></iframe>
  




  <p>Now my Big-O is a little rusty, but assuming our sort function is O-Nlog(N), our <strong>findAnagrams</strong>&nbsp;function should be O-M(NlogN) where M is the length of our input array and N is the length of the longest string in that array. That should be about as fast as this algorithm can get. Space complexity is O-3M in the worst case because we create and append to new instances of <strong>Set </strong>and <strong>Map.&nbsp;</strong>&nbsp;That <em>could</em>&nbsp;probably be reduced a bit at the expense of speed and clarity using a complex reduce function, but I'm happy with this solution.</p>]]></description></item><item><title>Welp. Tom Won.</title><category>Exposition</category><dc:creator>Zach Mayer</dc:creator><pubDate>Tue, 14 Nov 2017 17:22:41 +0000</pubDate><link>http://www.zachmayer.net/blog/2017/11/14/welp-tom-won</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:5a0b244df9619a1bb080166c</guid><description><![CDATA[<p>It's been almost two years since my last post and while I can make all sorts of excuses and present a ton of evidence for why my original goal of one blog a week didn't pan out, the fact remains that I got a measly 5 posts in before I quit.</p><p>Part of it was ambition outstripping realistic expectations. I simply don't have enough time to write the length of posts I thought I'd set out to write, and once I missed one week, then another week, and then another, it started to become easier to just ignore the blog altogether if only because the effort to bring it up to date just kept building.</p><p>So Tom wins. Go Tom.</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1510680408377-JQ3PWVAQY6RSHZWL3B3K/tomDoesntGiveAShit.png" data-image-dimensions="500x355" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1510680408377-JQ3PWVAQY6RSHZWL3B3K/tomDoesntGiveAShit.png?format=1000w" width="500" height="355" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1510680408377-JQ3PWVAQY6RSHZWL3B3K/tomDoesntGiveAShit.png?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1510680408377-JQ3PWVAQY6RSHZWL3B3K/tomDoesntGiveAShit.png?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1510680408377-JQ3PWVAQY6RSHZWL3B3K/tomDoesntGiveAShit.png?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1510680408377-JQ3PWVAQY6RSHZWL3B3K/tomDoesntGiveAShit.png?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1510680408377-JQ3PWVAQY6RSHZWL3B3K/tomDoesntGiveAShit.png?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1510680408377-JQ3PWVAQY6RSHZWL3B3K/tomDoesntGiveAShit.png?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1510680408377-JQ3PWVAQY6RSHZWL3B3K/tomDoesntGiveAShit.png?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>Source Lost To Time</p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>Without going into any details, some of the factors that kept me from posting often (or at all) have been eliminated, so I'm cautiously optimistic that I'll be able to start posting again. Maybe I'll even talk a bit about why blogging seems to be such a chore for me personally at some point, but I think I'll just stick with something simple for the foreseeable future.</p><p>I've recently started conducting interviews again, and I've come across some really great problems for candidates to solve on the phone screen as well as the whiteboard. A lot of them aren't original problems, but I think for the next several weeks at least I'll present solutions and explanations for some select problems that I like.</p><p> </p>]]></description></item><item><title>The Tao of a New Programmer</title><category>Exposition</category><dc:creator>Zach Mayer</dc:creator><pubDate>Wed, 03 Feb 2016 01:31:10 +0000</pubDate><link>http://www.zachmayer.net/blog/2016/1/29/the-tao-of-a-programmer</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:56abc3e6fb36b1cde31b014d</guid><description><![CDATA[<figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099634005-E9LAB7QLGOBQNFM1K0CD/image-asset.png" data-image-dimensions="300x279" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099634005-E9LAB7QLGOBQNFM1K0CD/image-asset.png?format=1000w" width="300" height="279" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099634005-E9LAB7QLGOBQNFM1K0CD/image-asset.png?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099634005-E9LAB7QLGOBQNFM1K0CD/image-asset.png?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099634005-E9LAB7QLGOBQNFM1K0CD/image-asset.png?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099634005-E9LAB7QLGOBQNFM1K0CD/image-asset.png?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099634005-E9LAB7QLGOBQNFM1K0CD/image-asset.png?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099634005-E9LAB7QLGOBQNFM1K0CD/image-asset.png?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099634005-E9LAB7QLGOBQNFM1K0CD/image-asset.png?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>via <a target="_blank" href="http://unifiedtao-en.blogspot.com/search/label/Tao">UnifiedTao</a></p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>I was reading a <a target="_blank" href="https://www.reddit.com/r/AskReddit/comments/43916z/if_you_were_20_again_what_skill_would_you_start/czgfllo">Reddit post</a>&nbsp;today in a thread about learning new skills and was inspired to consider my own answer to the question: "how does one learn to be a programmer?"</p><h2>The Logical Programmer</h2>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099877225-BLSCJSL0J7MA50YU4RXA/image-asset.png" data-image-dimensions="356x200" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099877225-BLSCJSL0J7MA50YU4RXA/image-asset.png?format=1000w" width="356" height="200" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099877225-BLSCJSL0J7MA50YU4RXA/image-asset.png?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099877225-BLSCJSL0J7MA50YU4RXA/image-asset.png?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099877225-BLSCJSL0J7MA50YU4RXA/image-asset.png?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099877225-BLSCJSL0J7MA50YU4RXA/image-asset.png?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099877225-BLSCJSL0J7MA50YU4RXA/image-asset.png?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099877225-BLSCJSL0J7MA50YU4RXA/image-asset.png?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454099877225-BLSCJSL0J7MA50YU4RXA/image-asset.png?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>via <a target="_blank" href="http://theycallmeswift.com/2013/06/11/principle-philosophy-for-developers-entrepreneurs-and-artists/">TheyCallMeSwift.com</a></p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <h3>Tao</h3><blockquote><em>The logical programmer is fundamentally a philosopher.&nbsp;</em></blockquote><p>Any extant philosophy can be applied to some aspect of software development, or programming more broadly if you bend just so, but in particular, programming is an exercise in creating ordered systems in a formal syntax. Implicitly,&nbsp;&nbsp;software is an expression of logic systems fist laid down in classical philosophy and formalized for mass consumption by <em><a target="_blank" href="https://en.wikipedia.org/wiki/The_Laws_of_Thought">The Laws of Thought</a> </em>by<em>&nbsp;</em>George Boole. A programmer in her aspect of philosopher builds systems of thought which follow a consistent line of reasoning, and it is in striving for an internally consistent philosophy that she produces Code, with a capital "C" rather than code.</p><h3>Dao</h3><p>In order to become a logical programmer, studying philosophy is a good first step. The experience of constructing philosophical proofs, one of the first things taught in many courses on the subject, is the programmer's most basic skill. Once the basics of inference and logic are well understood, it becomes second nature for the logical programmer to reason about ever more complex systems. A practiced philosopher may often elect to construct his own framework of thought to inspire his work.</p><h2>The Persistent Programmer</h2>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454454901969-OYM85TF3VDC9F3570BIJ/Einstein.png" data-image-dimensions="300x300" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454454901969-OYM85TF3VDC9F3570BIJ/Einstein.png?format=1000w" width="300" height="300" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454454901969-OYM85TF3VDC9F3570BIJ/Einstein.png?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454454901969-OYM85TF3VDC9F3570BIJ/Einstein.png?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454454901969-OYM85TF3VDC9F3570BIJ/Einstein.png?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454454901969-OYM85TF3VDC9F3570BIJ/Einstein.png?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454454901969-OYM85TF3VDC9F3570BIJ/Einstein.png?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454454901969-OYM85TF3VDC9F3570BIJ/Einstein.png?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454454901969-OYM85TF3VDC9F3570BIJ/Einstein.png?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>via <a target="_blank" href="https://www.etsy.com/people/AsspocketProductions">Etsy.com</a></p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <h3>Tao</h3><blockquote>The persistent programmer practices diligently.</blockquote><p>As with any craft or skill, practice makes all the difference. In Malcolm Gladwell's book,&nbsp;<a target="_blank" href="https://en.wikipedia.org/wiki/Outliers_(book)#Synopsis">Outliers: The Story Of Success</a>,&nbsp;it's claimed that 10,000 hours of practice marks the point at which one becomes a "phenom;" not just an expert, but a paragon of skill. For the persistent programmer that's not just time spent working at a programming job. In that setting more time is often consumed by tasks wholly unrelated to writing code than practicing the craft. Effective practice will reward effort with understanding.</p><h3>Dao</h3><p>Persistence is not only about practice, but as an initiate it should be the first focus. As a programmer, you will often find yourself up against very difficult problems. Some will have been solved before, and some will be completely novel, but the work to solve difficult problems is as much or more an exercise in persistence than cleverness.</p><blockquote><em>It’s not that I’m so smart, it’s just that I stay with problems longer.<br />- Albert Einstein (<a target="_blank" href="https://en.wikiquote.org/wiki/Talk:Albert_Einstein">attributed</a>)</em></blockquote><p>It's important to recognize that programmers practice not only to build upon the corpus of their knowledge and skill, but also to simply keep up with an ever-shifting landscape of tools, technologies, methodologies, and languages. As the complexity of the domain grows, it becomes absurd to think that any single person can master all disciplines in their entirety; it would be like trying to drink a waterfall.</p><p>Instead, programmers practice the most relevant skills with the most applicable tools for their current endeavors, focusing their efforts for maximum benefit in the short to medium term. In this way, expertise is fluid, and localized. Diligent practice is the paddle that keeps the persistent programmer from being washed down river.</p><h2>The Practical Programmer</h2>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462377289-XR4WQ9OO930KHRBRY86A/image-asset.jpeg" data-image-dimensions="1024x640" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462377289-XR4WQ9OO930KHRBRY86A/image-asset.jpeg?format=1000w" width="1024" height="640" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462377289-XR4WQ9OO930KHRBRY86A/image-asset.jpeg?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462377289-XR4WQ9OO930KHRBRY86A/image-asset.jpeg?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462377289-XR4WQ9OO930KHRBRY86A/image-asset.jpeg?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462377289-XR4WQ9OO930KHRBRY86A/image-asset.jpeg?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462377289-XR4WQ9OO930KHRBRY86A/image-asset.jpeg?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462377289-XR4WQ9OO930KHRBRY86A/image-asset.jpeg?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462377289-XR4WQ9OO930KHRBRY86A/image-asset.jpeg?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>Misty Mood by Leonid Afremov via <a target="_blank" href="https://afremov.com/MISTY-MOOD-PALETTE-KNIFE-Oil-Painting-On-Canvas-By-Leonid-Afremov-Size-24-x40.html">Afremov.com</a></p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <h3>Tao</h3><blockquote>&nbsp;The practical programmer is comfortable with abstraction.</blockquote><p>Programmers must be practical as a matter of course. Pragmatism with regards to the constraints of time and resources is a necessary and learned skill but for programming it mostly comes down to abstraction. A programmer who is comfortable with abstraction will not worry overmuch about the fine details of a system, but paint with broad strokes. There is not a person alive who understands computers and software in their entirety; from the bare silicon to your eyes. When someone explains how a web browser works, or how a memory bus functions, it's never (or rarely) to a level of completion such that someone could build the thing being explained from scratch, and that's ok because programmers, especially experienced programmers, become comfortable with abstractions early in their experience and learn to leverage those abstractions for a variety of purposes.</p><h3>Dao</h3><p>Abstractions are the programmer's bread and butter. Programmers speak in abstractions to peers in order to convey complex ideas succinctly and build upon them in the same way. By building on metaphors, the practical programmer not only reduces large problems to their basic components, but also shapes her philosophy from an ephemeral collection of broad ideas into a working model for practical application. Abstractions in software in the form of common libraries, tools, or frameworks lets the programmer focus less on the minutia of an application, and more on the problem at hand.</p><p>Since curiosity is so often a pronounced trait among aspiring programmers, the instinct to ask "how does that work?" is strong, and to be encouraged. Looking in depth into a particular function, algorithm, or tool leads one to appreciate the subject of one's study for it's utility and grace and may provide insight into how the virtues of a thing may be applied elsewhere, or how it's vices may manifest.&nbsp;When first learning to become a programmer, it's the tendency of many to become overwhelmed at the sheer depth and breadth of the discipline, and so neophytes, like children, easily fall into a trap of endlessly asking, "how?" and "why?" While curiosity is to be encouraged, it's important to remember that not everything needs to be perfectly understood in order to be useful. Accepting that some things work simply because they do, and allowing the abstraction of it all to be a comfort rather than a distraction will serve a nascent programmer far better in the near term.&nbsp;</p><h2>The Shrewd Programmer</h2>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462936508-1ONVJ9TBZ6BRCACE31M0/image-asset.png" data-image-dimensions="300x300" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462936508-1ONVJ9TBZ6BRCACE31M0/image-asset.png?format=1000w" width="300" height="300" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462936508-1ONVJ9TBZ6BRCACE31M0/image-asset.png?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462936508-1ONVJ9TBZ6BRCACE31M0/image-asset.png?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462936508-1ONVJ9TBZ6BRCACE31M0/image-asset.png?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462936508-1ONVJ9TBZ6BRCACE31M0/image-asset.png?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462936508-1ONVJ9TBZ6BRCACE31M0/image-asset.png?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462936508-1ONVJ9TBZ6BRCACE31M0/image-asset.png?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1454462936508-1ONVJ9TBZ6BRCACE31M0/image-asset.png?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>via <a target="_blank" href="http://store-xkcd-com.myshopify.com/products/try-science">XKCD.com</a> (attributed)</p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <h3>Tao</h3><blockquote>The shrewd programmer does not accept answers at face-value, but tests them.</blockquote><p>With the rise of the search engine, it's become ever easier to find answers to questions that arise in the course of solving a problem. The shrewd programmer sees these answers, or hears them from others, but doesn't not just nod and accept them without question. Rather, she will play with these answers and discover for herself what holds true. Experimentation is at the heart of learning to be a programmer. It is never enough to simply know a thing because it's been told. A new programmer should satisfy the desire to understand a thing by using it;&nbsp;probing it's limits and capabilities.</p><h3>Dao</h3><p>Never stop experimenting, and trust nothing completely that you have not verified. This is the corollary to The Practical Programmer, and speaks to the temperance of curiosity with pragmatism. Where abstractions let programmers be creative and scaffold the creation of complex systems, they also aren't always correct, and few (if any) are worthy of unconditional faith.</p><p>This is not to say that The Practical Programmer is a fool. If the new programmer never fails to ask "why?" or "how?" then no broader understanding may be gained until the utmost depth of a thing has been explored and understood, and it is The Practical Programmer who understands that breadth of knowledge and experience makes one flexible and adaptable. Likewise, if one simply accepts abstraction out of hand, and does not question the thing, it may break down in ways that can't easily be understood. The Shrewd Programmer learns to test assumptions, metaphors, and abstractions in such a way that they can be confident in them without the need to fully understand their inner workings completely. The Shrewd Programmer gains knowledge by responding to many of her own questions with the same answer, "let's find out!"</p><p>OUT.</p>]]></description></item><item><title>Expletives and Browsers</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Wed, 27 Jan 2016 00:22:17 +0000</pubDate><link>http://www.zachmayer.net/blog/2016/1/26/expletives-and-browsers</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:56a7d1995a56681988971025</guid><description><![CDATA[<figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453854416974-Q8S2D84ESTTTJEZLCI0M/image-asset.png" data-image-dimensions="232x300" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453854416974-Q8S2D84ESTTTJEZLCI0M/image-asset.png?format=1000w" width="232" height="300" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453854416974-Q8S2D84ESTTTJEZLCI0M/image-asset.png?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453854416974-Q8S2D84ESTTTJEZLCI0M/image-asset.png?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453854416974-Q8S2D84ESTTTJEZLCI0M/image-asset.png?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453854416974-Q8S2D84ESTTTJEZLCI0M/image-asset.png?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453854416974-Q8S2D84ESTTTJEZLCI0M/image-asset.png?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453854416974-Q8S2D84ESTTTJEZLCI0M/image-asset.png?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453854416974-Q8S2D84ESTTTJEZLCI0M/image-asset.png?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
      
        </figure>
      

    
  


  





  <p>I've been noticing a trend bubbling below the surface of the collective consciousness comprised of internet users of various stripes for a while now. To my perception, it appears that Internet Explorer has become much less reviled over time, and the generally high opinion of Chrome and Firefox has waned a bit in recent years. There are lots of reasons why that might or might not be the case, but I'm not interested in that at the moment. What I am interested in is "The Fuck Index" for the three most widespread web browsers.</p><p>If you don't know about the "The Fuck Index," <a target="_blank" href="http://www.urbandictionary.com/define.php?term=The+Fuck+Index">Urban Dictionary</a>&nbsp;does a decent job of explaining the concept thus:</p><blockquote><span>The Fuck Index (TFI), also known as The Google Fuck Poll, is a DIY poll like the Gallup Poll, but available to "we the people". It best used for measuring the relative popularity of key politicians, past and present. It is tested by doing a "Fuck &lt;enter name&gt;" on a Google Search, and reading the totals.</span></blockquote><p>It breaks down a bit outside of politics though. During a presidential campaign of a year or two, most people generate strong opinions and naturally seek an outlet for expressing them. Because people with strong opinions are often also lazy, that outlet is typically the path of least resistance, i.e., the Internet. The result is a lot of strong opinions can be expressed, cataloged, and counted within a relatively short time, giving you a reasonably informative statistic (as statistics go)&nbsp;for a time frame of a year or so. After a race the numbers stagnate and fewer people suddenly have such strong motivation to generate new data so it stops being representative of the current state of opinion.</p><p>And that's fine. It's only during a campaign where you're judging the hive-mind's disposition of current events that it's really relevant anyway. Just for grins, let's apply "The Fuck Index" to our targets:</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851545304-PFYNP7RKJOSAFT8URN42/image-asset.jpeg" data-image-dimensions="233x28" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851545304-PFYNP7RKJOSAFT8URN42/image-asset.jpeg?format=1000w" width="233" height="28" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851545304-PFYNP7RKJOSAFT8URN42/image-asset.jpeg?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851545304-PFYNP7RKJOSAFT8URN42/image-asset.jpeg?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851545304-PFYNP7RKJOSAFT8URN42/image-asset.jpeg?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851545304-PFYNP7RKJOSAFT8URN42/image-asset.jpeg?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851545304-PFYNP7RKJOSAFT8URN42/image-asset.jpeg?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851545304-PFYNP7RKJOSAFT8URN42/image-asset.jpeg?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851545304-PFYNP7RKJOSAFT8URN42/image-asset.jpeg?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>Fuck Firefox</p>
          </figcaption>
        
      
        </figure>
      

    
  


  













































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851645476-W9FW19LWOI82KIL47VLN/FuckChrome.JPG" data-image-dimensions="236x30" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851645476-W9FW19LWOI82KIL47VLN/FuckChrome.JPG?format=1000w" width="236" height="30" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851645476-W9FW19LWOI82KIL47VLN/FuckChrome.JPG?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851645476-W9FW19LWOI82KIL47VLN/FuckChrome.JPG?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851645476-W9FW19LWOI82KIL47VLN/FuckChrome.JPG?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851645476-W9FW19LWOI82KIL47VLN/FuckChrome.JPG?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851645476-W9FW19LWOI82KIL47VLN/FuckChrome.JPG?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851645476-W9FW19LWOI82KIL47VLN/FuckChrome.JPG?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851645476-W9FW19LWOI82KIL47VLN/FuckChrome.JPG?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>Fuck Chrome</p>
          </figcaption>
        
      
        </figure>
      

    
  


  













































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851590186-LCDRZ0V5H9Y5F7XFRMY6/image-asset.jpeg" data-image-dimensions="237x35" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851590186-LCDRZ0V5H9Y5F7XFRMY6/image-asset.jpeg?format=1000w" width="237" height="35" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851590186-LCDRZ0V5H9Y5F7XFRMY6/image-asset.jpeg?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851590186-LCDRZ0V5H9Y5F7XFRMY6/image-asset.jpeg?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851590186-LCDRZ0V5H9Y5F7XFRMY6/image-asset.jpeg?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851590186-LCDRZ0V5H9Y5F7XFRMY6/image-asset.jpeg?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851590186-LCDRZ0V5H9Y5F7XFRMY6/image-asset.jpeg?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851590186-LCDRZ0V5H9Y5F7XFRMY6/image-asset.jpeg?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453851590186-LCDRZ0V5H9Y5F7XFRMY6/image-asset.jpeg?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>Fuck Internet Explorer</p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>Interesting numbers so far, if only because the expected worst offender has the lowest number. I want to point out that I didn't use "Fuck IE" or "Fuck FF" for my samples because both of those are incredibly polluted. You can check them out yourself to see how. "Fuck Chrome" is likely corrupt in the same way, since "Chrome" is a perfectly cromulent word in its own right, irrespective of its relevance to web browsers. It's also worth mentioning that these numbers mean next to nothing simply because they don't reflect a change in opinion over time; just the average aggregate indignation suffered by people contributing to the corpus of the internet for all time. It's a poll, and polls are usually meant to capture information about a relatively small point in time which is why long-running polls are typically discounted out of hand.</p><p>"The Fuck Index" is deliciously ambiguous, because it relies on the ephemeral meaning of "fuck" to generate its primary metric. That means there are at least two ways we can interpret a large number of "fucks" given for a given search term as either a positive or negative response to suit our whim.</p><p>For my purpose, I want to gauge the relative popularity of, &nbsp;or frustration with, the most popular browsers, and people have been cursing all of them for a much longer time than your typical political campaign lasts. To that end, I turn to <a target="_blank" href="https://www.google.com/trends/">Google Trends</a>.</p><p>Let's see how our terms stack up as queries over time:</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
              
              
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852197439-PKSLHKVXH4UG5XTPYKCU/image-asset.jpeg" data-image-dimensions="852x495" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852197439-PKSLHKVXH4UG5XTPYKCU/image-asset.jpeg?format=1000w" width="852" height="495" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852197439-PKSLHKVXH4UG5XTPYKCU/image-asset.jpeg?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852197439-PKSLHKVXH4UG5XTPYKCU/image-asset.jpeg?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852197439-PKSLHKVXH4UG5XTPYKCU/image-asset.jpeg?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852197439-PKSLHKVXH4UG5XTPYKCU/image-asset.jpeg?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852197439-PKSLHKVXH4UG5XTPYKCU/image-asset.jpeg?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852197439-PKSLHKVXH4UG5XTPYKCU/image-asset.jpeg?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852197439-PKSLHKVXH4UG5XTPYKCU/image-asset.jpeg?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
            
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>via <a target="_blank" href="https://www.google.com/trends/explore#q=Fuck%20Firefox%2C%20Fuck%20Chrome%2C%20Fuck%20Internet%20Explorer&amp;cmpt=q&amp;tz=Etc%2FGMT%2B8">Google Trends</a></p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>Well that's neat! It appears that Chrome's Fuck Index is rising, while both Firefox and Internet Explorer's Fuck Indices are steadily falling. Also of note is that Internet Explorer's Fuck Index is historically significantly lower than the other two. Even changing the term to "Fuck IE doesn't show much difference:</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
              
              
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852510901-G3DUG7141O42LKWOIST5/image-asset.jpeg" data-image-dimensions="852x491" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852510901-G3DUG7141O42LKWOIST5/image-asset.jpeg?format=1000w" width="852" height="491" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852510901-G3DUG7141O42LKWOIST5/image-asset.jpeg?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852510901-G3DUG7141O42LKWOIST5/image-asset.jpeg?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852510901-G3DUG7141O42LKWOIST5/image-asset.jpeg?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852510901-G3DUG7141O42LKWOIST5/image-asset.jpeg?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852510901-G3DUG7141O42LKWOIST5/image-asset.jpeg?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852510901-G3DUG7141O42LKWOIST5/image-asset.jpeg?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453852510901-G3DUG7141O42LKWOIST5/image-asset.jpeg?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
            
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>via <a target="_blank" href="https://www.google.com/trends/explore#q=Fuck%20Firefox%2C%20Fuck%20Chrome%2C%20Fuck%20Internet%20Explorer%2C%20Fuck%20IE&amp;cmpt=q&amp;tz=Etc%2FGMT%2B8">Google Trends</a></p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>Call it confirmation bias (I certainly do), but it appears to confirm my suspicion. Chrome's fuckery is increasing, Firefox's fuckery is decreasing, and Internet Explorer's fuckery is less than both the other two and reaching equilibrium.</p><p>As for why this may be the case, I attribute the relative popularity differences among the three browsers to account for some of the wider discrepancies. Chrome's Fuck Index may be rising because it's now handily <a target="_blank" href="http://www.w3schools.com/browsers/browsers_stats.asp">the most popular browser on the web</a>, while Internet Explorer is in the single digits of market share.</p><p>In around 2011-2012, when the lines for Firefox and Chrome cross, their market shares were about equal, but Chrome has steadily grown in popularity since then. That might account for the decline in Firefox's fuckery since then, but in 2008, when the first big spike in Internet Explorer's Fuck Index appears, both Internet Explorer and Firefox has nearly equal user-bases; so why the rather large gap between them then?</p><p>At the end of the day, none of these number really mean much, and may in fact share more of a correlation with market share rather than vitriol or software quality. My perception remains, however: Internet Explorer is leveling off in terms of overall fuckery, and may very soon start making headway in recovering market share from Chrome. Meanwhile, Google is moving into position as the next giant browser in need of a harsh reality check.</p><p>I leave you with this:</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
              
              
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453853825845-9WSRYX3EQB3G4AN4YVTJ/image-asset.jpeg" data-image-dimensions="845x488" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453853825845-9WSRYX3EQB3G4AN4YVTJ/image-asset.jpeg?format=1000w" width="845" height="488" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453853825845-9WSRYX3EQB3G4AN4YVTJ/image-asset.jpeg?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453853825845-9WSRYX3EQB3G4AN4YVTJ/image-asset.jpeg?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453853825845-9WSRYX3EQB3G4AN4YVTJ/image-asset.jpeg?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453853825845-9WSRYX3EQB3G4AN4YVTJ/image-asset.jpeg?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453853825845-9WSRYX3EQB3G4AN4YVTJ/image-asset.jpeg?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453853825845-9WSRYX3EQB3G4AN4YVTJ/image-asset.jpeg?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453853825845-9WSRYX3EQB3G4AN4YVTJ/image-asset.jpeg?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
            
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>via Google Trends</p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>OUT.</p>]]></description><media:content type="image/jpeg" url="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453854130598-836SBPZNBNPKSONT9ALU/image-asset.jpeg?format=1500w" medium="image" isDefault="true" width="1500" height="1936"><media:title type="plain">Expletives and Browsers</media:title></media:content></item><item><title>Borders And Relativity</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Tue, 19 Jan 2016 00:55:07 +0000</pubDate><link>http://www.zachmayer.net/blog/2016/1/18/borders-and-relativity</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:569d784705f8e2b24daee4ca</guid><description><![CDATA[<p>EDIT/UPDATE Nov 2017<br />As of the last time I checked, the problem described below has been resolved in all modern browsers. The relevant bit of the CSS spec hasn't changed, but the example JSFiddle at the bottom will no longer show the odd state. Thank goodness for screenshots :)</p><p>Today I encountered an interesting bug. Actually no, that's not right. It's a dumb bug that shouldn't have been encountered at all, much less eaten up over an hour of my day. That I'm sitting here writing about it is as sure a sign that the bugs are winning as anything else.</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
              
              
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161046107-CV76H78HIHGACNMKULH2/bugswinning.jpg" data-image-dimensions="1366x734" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161046107-CV76H78HIHGACNMKULH2/bugswinning.jpg?format=1000w" width="1366" height="734" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161046107-CV76H78HIHGACNMKULH2/bugswinning.jpg?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161046107-CV76H78HIHGACNMKULH2/bugswinning.jpg?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161046107-CV76H78HIHGACNMKULH2/bugswinning.jpg?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161046107-CV76H78HIHGACNMKULH2/bugswinning.jpg?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161046107-CV76H78HIHGACNMKULH2/bugswinning.jpg?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161046107-CV76H78HIHGACNMKULH2/bugswinning.jpg?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161046107-CV76H78HIHGACNMKULH2/bugswinning.jpg?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
            
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>Would You Like To Know More?</p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>I'm still going to write about it because it touches on some undefined behavior in modern browsers and a small gap in the CSS3 spec so strap in kids it's gonna get messy.</p><h2>The Scenario</h2><p>The problem presented itself as a graphical hiccup in one of the tables our product features as a first-class feature. It's the first thing you see when you log in so it's kind of important that it not make us look like gibbering howler monkeys with keyboards.</p><p>Without showing too much of the yet-to-be-released product, here's what I saw when I opened the ticket:</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161316167-A9D2S7YTKH1X047BDAES/image-asset.jpeg" data-image-dimensions="1297x281" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161316167-A9D2S7YTKH1X047BDAES/image-asset.jpeg?format=1000w" width="1297" height="281" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161316167-A9D2S7YTKH1X047BDAES/image-asset.jpeg?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161316167-A9D2S7YTKH1X047BDAES/image-asset.jpeg?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161316167-A9D2S7YTKH1X047BDAES/image-asset.jpeg?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161316167-A9D2S7YTKH1X047BDAES/image-asset.jpeg?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161316167-A9D2S7YTKH1X047BDAES/image-asset.jpeg?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161316167-A9D2S7YTKH1X047BDAES/image-asset.jpeg?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453161316167-A9D2S7YTKH1X047BDAES/image-asset.jpeg?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>WAT.</p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>Something's clearly wrong. Really quick I'll go down the check-list of things it could be for you:</p><ol><li>Errant style on the row highlight class?&nbsp;</li><li>Extra border on the cell renderer?</li><li>Something to do with border-collapse weirdness?</li><li>A browser update to some relevant render pathway?</li><li>Some CSS3 animation overflow?</li><li>Positioning/Floating/Nesting of elements in or around the affected column?</li><li>Some JS render logic affecting this cell renderer in particular?</li></ol><p>You get the idea. The gist of the matter is this is likely something to do with an arcane composition of CSS/CSS3 that isn't playing nice.&nbsp;</p><p>Now before you ask: yes, I did look at the GIT history for the relevant files, and no I didn't immediately see the problem. Unfortunately, this bug snuck up on me and wasn't reported when it first manifested. That means I'd have had to comb through potentially weeks or months worth of changes to maybe spot the problem. Needle meet haystack. Besides, if the suspicion is correct, and this is some weird conjunction of evil spirits it wouldn't just be one easy-to-spot problem, it'd be several innocent looking changes that came together to make Voltron.</p><p>But I still got a little help from the ticket itself. It turns out no one noticed it because it didn't appear on every column (first), and it only seemed to appear briefly in the inital rendering of the table (second), while the loading animation for another column is running (third).</p><p>So by the first clue, I can safely say this isn't just a css issue affecting the whole table, but one targeted at a particular cell renderer. By the second clue it's apparent that something in the tables JS render pathway is capable of correcting the problem, a by the third clue, it's possible that CSS3 (the animation mechanism for the loading state) is a potential culprit.</p><p>Taking these one at a time, I decided to start with the cell renderer for the affected cells. Interestingly, the same cell renderer is used by multiple columns in the table but only some show the bugged behavior. Even moving the columns around in the table makes the problem appear on different cells. Still, the affected cells are all the same type with the same renderer. Something might be wrong with the cell renderer but I don't know exactly what it could be.</p><p>Setting aside the cell renderer I started looking more closely at reproducing the problem in a stable state. In order to keep the bugged columns from fixing themselves later in the table's render cycle, I started interrupting the renderer of the whole table at different points to pin down when the problem self-corrects. It turns out the problem is only expressed when the loading animation is present on some rows, and only for rows with different background-colors than white.</p><p>So stopping the animation got me to this state:</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453162959938-W8JZEF5HCXJY8RXCGLU1/image-asset.jpeg" data-image-dimensions="1296x282" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453162959938-W8JZEF5HCXJY8RXCGLU1/image-asset.jpeg?format=1000w" width="1296" height="282" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453162959938-W8JZEF5HCXJY8RXCGLU1/image-asset.jpeg?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453162959938-W8JZEF5HCXJY8RXCGLU1/image-asset.jpeg?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453162959938-W8JZEF5HCXJY8RXCGLU1/image-asset.jpeg?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453162959938-W8JZEF5HCXJY8RXCGLU1/image-asset.jpeg?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453162959938-W8JZEF5HCXJY8RXCGLU1/image-asset.jpeg?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453162959938-W8JZEF5HCXJY8RXCGLU1/image-asset.jpeg?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1453162959938-W8JZEF5HCXJY8RXCGLU1/image-asset.jpeg?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>Progress?</p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>Might be progress. CSS3 animation is clearly a factor, but it turns out I can get the same result by simply setting "border-collapse: separate" for the table. Unfortunately, I need the borders to collapse or the positioning of the columns with their headers won't work out and I'll have to go back through some really gnarly table render code to make the change fit.</p><p>Surely there's a simpler solution?</p><p>Turns out there was.&nbsp;</p><p>When I was first looking at the affected cell renderer I had neglected to look at it's context in the table and as it happens, these particular cells were being rendered with "position: relative;"</p><p>Now that's not such a terrible thing under most circumstances. Tables all over the internet have cells with relative positioning for one reason or another, and why these cells were positioned that way I can't go in to but suffice to say that's a pretty innocuous attribute of a table cell.</p><h2>The solution</h2><p>Taking a step back, we have three things which might combine to cause problems:</p><ol><li>CSS3 Animations in a table cell</li><li>Border-collapse</li><li>Cells with position:relative</li></ol><p>The last two when combined <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=688556">are known to cause problems</a>&nbsp;but it's a pretty well known problem in almost every major browser since the dawn of time. The reason it's an issue at all, and especially why the same problem presents itself differently in every browser is because of this lovely gap in the <a target="_blank" href="https://www.w3.org/TR/CSS21/visuren.html#propdef-position">W3C CSS2.1 Spec</a>:</p><blockquote><span>The effect of 'position:relative' on table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell, and table-caption elements is undefined.</span></blockquote><p>Neat huh?</p><p>There are tricks and work-arounds for this kind of problem, and I'd already implemented a couple to make the table cells render properly in the first place, but with the introduction of the loading animation things got weird again. It turns out that even if you know all the tricks to dealing with border-collapsed cells with defined borders and relative positioning, CSS3 animations can still come through to fuck up your day, presumably because the animation affects the render model (box or otherwise) preventing certain repaints from occurring when a transformation is in play.</p><p>The solution? DON'T USE POSITION:RELATIVE ON TABLE CELLS.</p><p>In my case I just had to remove the positioning from the cell and move it to an interior container that spanned the height/width of the cell itself.</p><p>If you want to play with the problem I've put together a fiddle for you. Enjoy!</p>
























  
    
  <iframe allowfullscreen="allowfullscreen" src="//jsfiddle.net/ZachMayer/4ur8or9c/embedded/" width="100%" frameborder="0" height="300"></iframe>]]></description></item><item><title>JS Micro-Perf: Array.map</title><category>Software</category><dc:creator>Zach Mayer</dc:creator><pubDate>Tue, 12 Jan 2016 23:10:00 +0000</pubDate><link>http://www.zachmayer.net/blog/2016/1/5/js-micro-perf-arraymap</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:568c4d8425981da9388f54f5</guid><description><![CDATA[<p>Today I had a familiar argument regarding Javascript micro-optimizations. This time we were mulling the virtues and vices of Array functions like map, reduce, filter, etc., and the performance variance among different implementations (underscore/lodash, Array.prototype, home-grown and such).&nbsp;As always my first stop was <a target="_blank" href="http://jsperf.com">jsperf.com</a>.</p><p>Take a look at these results:</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
              
              
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038833810-5NE8389XAZ2EJAPE9X2U/JSPerf.JPG" data-image-dimensions="968x582" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038833810-5NE8389XAZ2EJAPE9X2U/JSPerf.JPG?format=1000w" width="968" height="582" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038833810-5NE8389XAZ2EJAPE9X2U/JSPerf.JPG?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038833810-5NE8389XAZ2EJAPE9X2U/JSPerf.JPG?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038833810-5NE8389XAZ2EJAPE9X2U/JSPerf.JPG?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038833810-5NE8389XAZ2EJAPE9X2U/JSPerf.JPG?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038833810-5NE8389XAZ2EJAPE9X2U/JSPerf.JPG?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038833810-5NE8389XAZ2EJAPE9X2U/JSPerf.JPG?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038833810-5NE8389XAZ2EJAPE9X2U/JSPerf.JPG?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
            
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>Source: <a target="_blank" href="https://jsperf.com/native-vs-array-js-vs-underscore/174">JSPerf.com</a></p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>Pretty much what you expected right? The Array.prototype.map function is like, 5 to 7 times slower than underscore/lodash and 18 times slower than a plain old for loop. Even jQuery's notoriously slow map function beats it.</p><p>What struck me however was that there are a couple of ways to make that for loop above <em>even faster</em>&nbsp;so I wanted to see just <em>how </em>fast it could go. That led me to create this micro-perf-test:</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
              
              
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038139548-9EK2ZWYYKY6OQ34W7E6J/image-asset.jpeg" data-image-dimensions="975x624" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038139548-9EK2ZWYYKY6OQ34W7E6J/image-asset.jpeg?format=1000w" width="975" height="624" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038139548-9EK2ZWYYKY6OQ34W7E6J/image-asset.jpeg?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038139548-9EK2ZWYYKY6OQ34W7E6J/image-asset.jpeg?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038139548-9EK2ZWYYKY6OQ34W7E6J/image-asset.jpeg?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038139548-9EK2ZWYYKY6OQ34W7E6J/image-asset.jpeg?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038139548-9EK2ZWYYKY6OQ34W7E6J/image-asset.jpeg?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038139548-9EK2ZWYYKY6OQ34W7E6J/image-asset.jpeg?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1452038139548-9EK2ZWYYKY6OQ34W7E6J/image-asset.jpeg?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
            
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>Source: <a target="_blank" href="http://jsperf.com/map-function-micro-optimization">JSPerf.com</a></p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>More than doubled the performance of the map by simply allocating the array up front and avoiding "push" overhead.&nbsp;Moral of the story? Allocation is expensive. Pay attention to your heap changes the same way you care about repaint/reflow and your apps will run like the wind.</p><p>Of course, these kinds of micro-optimizations often as not aren't worth the code bloat and subsequent headache to maintain over a nice, handy library function, but it's helpful to know that the native Array.prototype functions are simply dog slow and almost anything will perform better.</p><p>Counter-intuitive, but the data speaks.</p><p>OUT.</p>]]></description></item><item><title>New Year New Website</title><category>Exposition</category><dc:creator>Zach Mayer</dc:creator><pubDate>Tue, 05 Jan 2016 10:34:00 +0000</pubDate><link>http://www.zachmayer.net/blog/2016/1/5/new-year-new-website</link><guid isPermaLink="false">568b00a325981da938837417:568b00de1115e0d0bc136d6a:568b00ff1115e0d0bc136eab</guid><description><![CDATA[<figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="true" data-image="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1451989398064-W4H7Z542V87PS2N57UOY/image-asset.jpeg" data-image-dimensions="500x299" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" src="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1451989398064-W4H7Z542V87PS2N57UOY/image-asset.jpeg?format=1000w" width="500" height="299" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1451989398064-W4H7Z542V87PS2N57UOY/image-asset.jpeg?format=100w 100w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1451989398064-W4H7Z542V87PS2N57UOY/image-asset.jpeg?format=300w 300w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1451989398064-W4H7Z542V87PS2N57UOY/image-asset.jpeg?format=500w 500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1451989398064-W4H7Z542V87PS2N57UOY/image-asset.jpeg?format=750w 750w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1451989398064-W4H7Z542V87PS2N57UOY/image-asset.jpeg?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1451989398064-W4H7Z542V87PS2N57UOY/image-asset.jpeg?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1451989398064-W4H7Z542V87PS2N57UOY/image-asset.jpeg?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption class="image-caption-wrapper">
            <p>Image Credit <a target="_blank" href="http://todaymade.com/blog/new-year-resolutions/">Todaymade Blog</a></p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <p>Well here I am in 2016. I've retired my old website that I hadn't updated in over 4 years and high on the adrenaline from my new role as co-host of <a target="_blank" href="http://qq-cast.com">The QQ Cast</a>&nbsp;I'm officially starting a blog. Ok maybe it's not adrenaline. Maybe I'm looking at my pod-casting co-host <a target="_blank" href="http://tomdupont.net">Tom's</a> internet presence and finally starting to feel inadequate.</p><p>Thanks Tom.</p><p>So what am I going to blog about? Well whatever I feel like I suppose. I started this website update with the intention of creating a new place to which I could link people looking for more information on me as a professional. That'll likely be the primary mission of the site, but I'm not going to pigeon-hole myself right off the bat.</p><p>As part of my litany of unmanageable new year's resolutions I'm hereby vowing to update this blog with <em>something </em>at least once per week. Even Tom can't say he's done 52 blog posts in a calendar year. Heh.</p><p>So I guess that's it. I'm starting a blog. It's a new year of adventures ahead and some wonderful memories behi-oh my god it's like I'm turning into a cliché as I type. Geez. That's it. I'm signing off. We'll see what next week's update looks like.</p><p>OUT.</p>]]></description><media:content type="image/jpeg" url="https://images.squarespace-cdn.com/content/v1/568b00a325981da938837417/1451990157336-CI1LBP05IB8W78GIQHU3/image-asset.jpeg?format=1500w" medium="image" isDefault="true" width="500" height="299"><media:title type="plain">New Year New Website</media:title></media:content></item></channel></rss>