<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>tuesdayDeveloper;</title>
    <description>tech opinions and how-tos</description>
    <link>http://tuesdaydeveloper.com/</link>
    <atom:link href="http://tuesdaydeveloper.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sat, 27 Apr 2024 22:30:50 +0000</pubDate>
    <lastBuildDate>Sat, 27 Apr 2024 22:30:50 +0000</lastBuildDate>
    <generator>Jekyll v3.9.5</generator>
    
      <item>
        <title>The Nexus is Dead, Long Live the Nexus</title>
        <description>&lt;p&gt;&lt;img src=&quot;http://tuesdaydeveloper.com/assets/nexus-def.png&quot; alt=&quot;Nexus&quot; /&gt;&lt;/p&gt;

&lt;p&gt;By definition, Nexus means a connection or series of connections linking two or more things. Well, in light of the new Pixel phones the Nexus is getting disconnected.&lt;/p&gt;

&lt;p&gt;Oh sure, there should still be security updates, but where as Pixel phones get the new Google Assistant, Nexus phones do not. Where Pixel phones get unlimited storage for &lt;em&gt;full-resolution&lt;/em&gt; photos and videos (including 4K), Nexus phones are lumped with the rest of the average and sub-par phones of the world and their resolution is downgraded to “high-quality” whatever that means.&lt;/p&gt;

&lt;p&gt;I feel like Google has abandoned all about their loyal Nexus children (unless they upgrade). I don’t think I’m the only one who feels that way. Despite my years of campaigning to friends and family about the virtuous Nexus line (&lt;strong&gt;the one that was supposed to always have the latest and greatest directly from Google&lt;/strong&gt;) I and many other loyal Nexus owners are forgotten. Because of these broken promises I’ll be more hesitant to recommend a Google phone (whatever the name) in the future&lt;sup id=&quot;fnref:recommendations&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:recommendations&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Don’t get me wrong, I think the Pixel looks great. I’m not crazy about the half and half back with glass and metal&lt;sup id=&quot;fnref:weird&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:weird&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, but I wasn’t crazy about the camera hump on my Nexus 6p either&lt;sup id=&quot;fnref:6phump&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:6phump&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. I could make an argument that it’s in Google best interest to release Google Assistant to all phones (not just Pixel/Nexus phones) or that Google competitors offer unlimited full-res photo storage&lt;sup id=&quot;fnref:competitors&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:competitors&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;, but in light of their latest move I’m not confident that they would see reason.&lt;/p&gt;

&lt;iframe width=&quot;740&quot; height=&quot;416&quot; src=&quot;https://www.youtube.com/embed/Rykmwn0SMWU&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;But I’m not ready to upgrade&lt;sup id=&quot;fnref:upgrade&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:upgrade&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;. I had sticker shock, but it’s more than that. Despite the Pixel commercial telling me otherwise, I didn’t see anything new in the Pixel phone. Sure there’s more RAM and more processor, but the rest of the updates are all software, including the camera&lt;sup id=&quot;fnref:camera&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:camera&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;In short, I felt the Nexus promise was that I wouldn’t feel like I was being forgotten (like every other phone manufacturer). What makes companies fail&lt;sup id=&quot;fnref:fail&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:fail&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;? Poor customer service, making customers feel like they’re forgotten.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:recommendations&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Recommendations are the most important marketing tactic your product can have. &lt;a href=&quot;#fnref:recommendations&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:weird&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;That just looks weird. &lt;a href=&quot;#fnref:weird&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:6phump&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I got used to it. &lt;a href=&quot;#fnref:6phump&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:competitors&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;a href=&quot;https://shoeboxapp.com/&quot;&gt;ShoeBox&lt;/a&gt; &lt;a href=&quot;https://www.amazon.com/clouddrive/primephotos&quot;&gt;Amazon Prime&lt;/a&gt; Yes, it’s true neither of these offer unlimited video storage. Google should be better than that. &lt;a href=&quot;#fnref:competitors&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:upgrade&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I can’t justify a new phone every year. &lt;a href=&quot;#fnref:upgrade&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:camera&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I get that the new image stabilization may need more RAM, but it’s still a software change. &lt;a href=&quot;#fnref:camera&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:fail&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I’m not talking about bankruptcy, I think Google as a whole will do just fine. &lt;a href=&quot;#fnref:fail&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 05 Oct 2016 19:34:56 +0000</pubDate>
        <link>http://tuesdaydeveloper.com/google/nexus/pixel/venting/2016/10/05/long-live-nexus.html</link>
        <guid isPermaLink="true">http://tuesdaydeveloper.com/google/nexus/pixel/venting/2016/10/05/long-live-nexus.html</guid>
        
        
        <category>google</category>
        
        <category>nexus</category>
        
        <category>pixel</category>
        
        <category>venting</category>
        
      </item>
    
      <item>
        <title>Flattening Vectors</title>
        <description>&lt;p&gt;Recently I was working on a problem where I needed to get a vector of vectors containing an entry
for every possible path when given a vector which might contains scalar values or vectors of scaler
values.&lt;/p&gt;

&lt;p&gt;Some examples:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
        &lt;th&gt;input&lt;/th&gt;&lt;th&gt;output&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
        &lt;td&gt;[:a]&lt;/td&gt;&lt;td&gt;[[:a]]&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;[1]&lt;/td&gt;&lt;td&gt;[[1]]&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;[:a :b :c]&lt;/td&gt;&lt;td&gt;[[:a :b :c]]&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;[:a [:b]]&lt;/td&gt;&lt;td&gt;[[:a :b]]&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;[:a [:b :c]]&lt;/td&gt;&lt;td&gt;[[:a :b] [:a :c]]&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;[[:a :b] [:c :d]]&lt;/td&gt;&lt;td&gt;[[:a :c] [:a :d] [:b :c] [:b :d]]&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Here is my solution to the problem:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pathcrawler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add-key&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;computed&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;case&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;empty?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;computed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;coll?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;conj&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;computed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;computed&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                       &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;conj&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;computed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;conj&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compute-paths&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Returns all single dementional path-sets from a given path.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;compute-paths&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path-suffix&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;computed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;not-empty&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path-suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;recur&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path-suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add-key&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;computed&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path-suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;computed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Tests:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;deftest&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test-compute-paths&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;are&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pathcrawler/compute-paths&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                         &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                              &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                              &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                              &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:c&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:m&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:y&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:m&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:m&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:m&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:n&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:n&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:n&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:m&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:m&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:m&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:n&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:n&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:n&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As it turns out, I can’t use it. I might as well post it.&lt;/p&gt;
</description>
        <pubDate>Wed, 14 Sep 2016 22:34:56 +0000</pubDate>
        <link>http://tuesdaydeveloper.com/clojure/2016/09/14/flattinging-vectors.html</link>
        <guid isPermaLink="true">http://tuesdaydeveloper.com/clojure/2016/09/14/flattinging-vectors.html</guid>
        
        
        <category>clojure</category>
        
      </item>
    
      <item>
        <title>My Use for Multi-window</title>
        <description>&lt;p&gt;Early on when I started using Android I often wished that I could have two apps open at once—with
Android Nougat I can do that now, but…&lt;/p&gt;

&lt;p&gt;Well, even though I’ve been Nougat on the beta channel for several months, there’s just one
thing I really found this feature useful for. And for that one use, I hope they keep it forever!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://tuesdaydeveloper.com/assets/2016-08-25-recipe.png&quot; alt=&quot;Side-by-side Recipe&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s right, I have the Chrome app and Chrome Beta open to the same recipe so I can see the
ingredient list and the cooking instructions side-by-side!&lt;/p&gt;

&lt;p&gt;Now if only I could get Android to not only lock in portrait mode, but also in landscape mode. 
(Without a third party app, ‘cause they’re all too ugly.)&lt;/p&gt;
</description>
        <pubDate>Thu, 25 Aug 2016 22:34:56 +0000</pubDate>
        <link>http://tuesdaydeveloper.com/android/2016/08/25/my-use-for-multi-window.html</link>
        <guid isPermaLink="true">http://tuesdaydeveloper.com/android/2016/08/25/my-use-for-multi-window.html</guid>
        
        
        <category>android</category>
        
      </item>
    
      <item>
        <title>Why Your Program Looks Awful</title>
        <description>&lt;p&gt;A cautionary tale of application development.&lt;/p&gt;

&lt;h2 id=&quot;sprint-1&quot;&gt;Sprint 1&lt;/h2&gt;

&lt;h4 id=&quot;story-1-feature&quot;&gt;story 1 (feature)&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Estimation:&lt;/strong&gt; 5&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Specification:&lt;/strong&gt; Create a plane figure with three straight lines of equal length that meet at the ends forming a total of three interior equiangular angles.&lt;/p&gt;

&lt;h3 id=&quot;sprint-1-result&quot;&gt;Sprint 1 Result&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;http://tuesdaydeveloper.com/assets/11jul2016-sprint1.png&quot; alt=&quot;Sprint 1 Result&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A plane figure with three relatively straight lines with one line only slightly longer than the other two forming three interior angles, close to equal. We are only human, we can’t draw perfectly.&lt;/p&gt;

&lt;p&gt;We receive accolades for a sprint well done.&lt;/p&gt;

&lt;h2 id=&quot;sprint-2&quot;&gt;Sprint 2&lt;/h2&gt;

&lt;h4 id=&quot;story-2-bug&quot;&gt;story 2 (bug)&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Estimation:&lt;/strong&gt; 5&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Specification&lt;/strong&gt; The longer line needs to be shortened to be equal to the other two, lines still need to meet. Oh, and can you make it blue?&lt;/p&gt;

&lt;h4 id=&quot;story-3-feature&quot;&gt;story 3 (feature)&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Specification&lt;/strong&gt; We need to have a fourth side added to our figure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Estimation:&lt;/strong&gt; 2&lt;/p&gt;

&lt;h3 id=&quot;sprint-2-result&quot;&gt;Sprint 2 Result&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;http://tuesdaydeveloper.com/assets/11jul2016-sprint2.png&quot; alt=&quot;Sprint 2 Result&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A figure that looks like that of the first (with a few lines erased and redrawn leaving some artifacts of old code) one of the lines is now blue. On the top there is a fourth side protruding (like a tangent) that does not connect to anything. &lt;em&gt;In the defense of the programmers, this is a perfectly valid response to the specifications that were given.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;sprint-3&quot;&gt;Sprint 3&lt;/h2&gt;

&lt;h4 id=&quot;story-4-bug&quot;&gt;story 4 (bug)&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Specification&lt;/strong&gt; Connect the end of line three with the end of line four.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Estimation:&lt;/strong&gt; 2&lt;/p&gt;

&lt;h3 id=&quot;sprint-3-result&quot;&gt;Sprint 3 Result&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;http://tuesdaydeveloper.com/assets/11jul2016-sprint3.png&quot; alt=&quot;Sprint 3 Result&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It looks like a rhombus, with a few lines erased.&lt;/p&gt;

&lt;p&gt;We relieve hesitant pats on the back right after they ask why we only got 2 points of work done when we got 7 done last spring and 5 the sprint before.&lt;/p&gt;

&lt;h2 id=&quot;ad-infinitum&quot;&gt;ad infinitum&lt;/h2&gt;

&lt;p&gt;This results in Sprint 4 which asks to make all connecting lines perfectly perpendicular (because what they wanted the whole time was a square), and the process continues.&lt;/p&gt;

&lt;h2 id=&quot;programming-vs-building-cars&quot;&gt;Programming vs. Building Cars&lt;/h2&gt;

&lt;p&gt;Building programs is a lot like building cars—you have to smash a few to make sure the rest are safe. We rarely understand what a program should look like from the beginning. It takes a lot of deliberate thought and patience before the design of an application emerges. Sometimes you have to try and fail so you know how to try again. People do this in other fields too. Successful entrepreneurs will tell you that their first 50 businesses were failures. Published authors will speak of their many, many rejection letters. Artists, rarely become famous overnight. Sometimes programmers will have to try out one design before they realize its flaws.&lt;/p&gt;

&lt;p&gt;But programming is also like raising children. Parents &lt;em&gt;may not&lt;/em&gt; smash their children! Even if they mess up. If you mess up somehow (maybe you lose your temper and yell) you have to work with the result. Sometimes the application you have in production is what you have to work with and you can’t just start over. But you’re still going to make mistakes, so what do you do?&lt;/p&gt;

&lt;p&gt;This is what agile is all about. You get to define the parameters over how frequently you might fail but not whether you will fail. Sometimes you have to refactor greatly (e.g. even throw away part of your code) so that the program delivered is the program being asked for. The initial architecture of an application may not be what you will want to end up with and so you have to change it. But you have to work with what you’ve got now to produce what you really need.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-math&quot; data-lang=&quot;math&quot;&gt;x = current application

f(x) =&amp;gt; x'&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You’ll notice that there were lines that didn’t get completely erased in the example above. These should have been removed, but we ran out of sprint and so they’ll probably live there until some poor soul comes along and wonders what on earth this is supposed to do and he asks a lot of questions about the code and he maybe (in a fit of bravery) removes it, is relieved that all the tests pass, but he doesn’t sleep well for a couple nights because he’s afraid that he’ll get a call reporting some error in the application due to the code that didn’t seem to do anything….&lt;/p&gt;

&lt;h2 id=&quot;how-to-fix-it&quot;&gt;How to fix it&lt;/h2&gt;

&lt;p&gt;Like many things the only thing we can do is be careful and attentive in our work. We have to take time to think and design &lt;em&gt;before&lt;/em&gt; we start coding. There’s a great quote I heard recently “I find that weeks of coding and testing can save me hours of design.”&lt;sup id=&quot;fnref:design&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:design&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; We have to double check our work after we commit, and it’s really helpful if we take time to make the code we just finished easier to read. Ask your neighbor if he understands the code in its current state. Refactor until you think it’s easier to understand.&lt;/p&gt;

&lt;h2 id=&quot;problems-out-of-our-hands&quot;&gt;Problems out of our hands&lt;/h2&gt;

&lt;p&gt;There are problems that are implicit to the tools we use or the domain we’re in. We should try to reduce complexity as much as possible. Use a better tool if possible, but there will still be some things that will be complicated about our application whether we like it or not. I still believe that we should refactor to simplicity as much as we can, knowing that there may be a limit.&lt;/p&gt;

&lt;h2 id=&quot;its-only-going-to-be-used-once&quot;&gt;It’s only going to be used once&lt;/h2&gt;

&lt;p&gt;If your application is only going to be used one time to parse a million records from one format and input them into another, maybe you don’t have to follow these rules. If there is even a chance that you or anyone else will have to read the code again, I urge you to take some time to save time down the road.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:design&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I’m sorry I couldn’t find a source for this. &lt;a href=&quot;#fnref:design&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Mon, 11 Jul 2016 19:34:56 +0000</pubDate>
        <link>http://tuesdaydeveloper.com/design/agile/2016/07/11/why-your-program-looks-awful.html</link>
        <guid isPermaLink="true">http://tuesdaydeveloper.com/design/agile/2016/07/11/why-your-program-looks-awful.html</guid>
        
        
        <category>design</category>
        
        <category>agile</category>
        
      </item>
    
      <item>
        <title>A New Beginning!</title>
        <description>&lt;p&gt;I’ve been blogging here for more than six years and I’m now excited to announce that I’m transitioning my blog from WordPress to Jekyll (because it’s cool). You’ve probably&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; already noticed the blog layout change which is likely to continue to change in the sort term.&lt;/p&gt;

&lt;p&gt;You’ll also have noticed, my astute reader, that you can’t post comments… I’m working on that.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Unless you don’t read my blog regularly, which you should start, though I can’t really blame you because it’s not like there is a lot of new content here on a regular basis. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 15 Jun 2016 23:30:42 +0000</pubDate>
        <link>http://tuesdaydeveloper.com/housekeeping/2016/06/15/a-new-beginning.html</link>
        <guid isPermaLink="true">http://tuesdaydeveloper.com/housekeeping/2016/06/15/a-new-beginning.html</guid>
        
        
        <category>housekeeping</category>
        
      </item>
    
      <item>
        <title>Rounding Errors</title>
        <description>&lt;p&gt;I’m not really sure why, but since I learned about rounding errors I’ve always been fascinated by them. Case in point, I was playing with Clojure’s (range) function and:&lt;/p&gt;

&lt;pre lang=&quot;clojure&quot;&gt;(range 0.1 1.1 0.1)
=&amp;gt;(0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7 0.7999999999999999 0.8999999999999999 0.9999999999999999 1.0999999999999999&lt;/pre&gt;

&lt;p&gt;When I tried this out I was expecting ten results—not eleven—something more like:&lt;/p&gt;

&lt;pre lang=&quot;clojure&quot;&gt;(map #(/ % 10.0) (range 1 11))
=&amp;gt;(0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0)&lt;/pre&gt;
</description>
        <pubDate>Tue, 09 Feb 2016 12:34:43 +0000</pubDate>
        <link>http://tuesdaydeveloper.com/2016/02/09/rounding-errors.html</link>
        <guid isPermaLink="true">http://tuesdaydeveloper.com/2016/02/09/rounding-errors.html</guid>
        
        
      </item>
    
      <item>
        <title>The Cause of Poor Code</title>
        <description>&lt;p&gt;I said in my last post that I felt that the various codebases I’ve worked on were junk. I however do not think that the various programmers I’ve worked with were poor programmers. While every programmer surly makes mistakes once in a while the truth of the matter isn’t so black and white. There are a couple reasons our precious code base devolves into a disorganized mess. While there are undeniably many reasons for poor code quality, I’ll address the two that I think are the most predominant.&lt;/p&gt;
&lt;h3&gt;Handling Dynamic Requirements&lt;/h3&gt;
&lt;p&gt;When a new project is started, some understanding of what it will do must be delivered to the developers who will be working on it. This is a deliverable from the customers to the developers. It is an unfortunate truth, however, that users don’t know what they want. We can’t blame them for this, it’s often hard to describe, technical know-how is lacking, and even if things are exactly as planned they often don’t hold up to the thing you envisioned in your head. This enumeration is usually true for developers as well. But, even if we don’t blame this problem, it still causes issues (you have to understand a problem to solve it!).&lt;/p&gt;

&lt;p&gt;But it doesn’t stop there. As will invariably happen, even if the requirements were perfectly understood, once a user (or his/her replacement) has had a chance to use the tool you built or after a few weeks, months, or years, a new requirement will pop up. Working with updated requirements will cause difficulties in our code base if handled incorrectly. I am not implying that changing requirements are a problem, it’s what developers do with the changing requirements that can be a problem.  It is perfectly natural for requirements to change and it should be part of any Agile project. The issue arises when a coder looks at the new requirement and (without doing a proper refactor) tries to make it work the same way another feature works when it wasn’t ever intended to work that way.&lt;/p&gt;
&lt;h4&gt;The Solution&lt;/h4&gt;
&lt;p&gt;This is hardly the worst offender, but it is an issue. As eluded to above the solution for this problem is relatively simple (at least on paper): relentless refactoring.&lt;/p&gt;

&lt;p&gt;One of the reasons Relentless Refactoring is prized so much in Extreme Programming is because requirements are continually evolving and changing. Dynamic requirements demand dynamic code, a fresh look at the answer to yesterday’s problem and a conscience effort to morph it into the answer for today’s problem. This does not imply that we will do the minimum necessary to get it to work and it certainly doesn’t imply that we will copy and paste some code and then make a few tweaks to it here and there. It means that we will iteratively take the code we have and change it into the code we need. Sometimes the answer is easy, sometimes a refactor involves substantially new code.&lt;/p&gt;
&lt;h3&gt;Deadlines&lt;/h3&gt;
&lt;p&gt;The next issue seems to often be the cause for a lack of proper refactoring: deadlines. Below I’ve quoted the best description I’ve ever seen that describes the next problem:&lt;/p&gt;
&lt;p style=&quot;padding-left: 30px;&quot;&gt;A Big Ball of Mud is a haphazardly structured, sprawling, sloppy, duct-tape-and-baling-wire, spaghetti-code jungle. These systems show unmistakable signs of &lt;em&gt;unregulated growth&lt;/em&gt;, and &lt;em&gt;repeated, &lt;strong&gt;expedient&lt;/strong&gt; repair&lt;/em&gt;. Information is shared promiscuously among distant elements of the system, often to the point where nearly all the important information becomes global or duplicated. The overall structure of the system may never have been well defined. If it was, it may have eroded beyond recognition. Programmers with a shred of architectural sensibility shun these quagmires. Only those who are unconcerned about architecture, and, perhaps, are comfortable with the inertia of the day-to-day chore of patching the holes in these failing dikes, are content to work on such systems.&lt;/p&gt;
&lt;p style=&quot;padding-left: 30px;&quot;&gt;—Brian Foote and Joseph Yoder, &lt;i&gt;Big Ball of Mud.&lt;/i&gt; Fourth Conference on Patterns Languages of Programs (PLoP '97/EuroPLoP '97) Monticello, Illinois, September 1997 (emphasis added, this quote was copied from the Wikipedia entry on &lt;a href=&quot;http://en.wikipedia.org/wiki/Big_ball_of_mud&quot;&gt;Big Ball of Mud&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Software engineers are often between a rock and a firearm when a new feature is requested. Every once in a while a manager will say that X (very large) Project needs to be done by Y (way to soon) date. I’ll let you in on a little secret: this is counter productive. Few developers work better under pressure. Developers (and I’d argue everyone) work best with enough work to keep us busy, but not so much that we don’t get to see our families or have a weekend.&lt;/p&gt;

&lt;p&gt;What is often most frustrating in these situations (it’s happened this way to me before) is that the manager knew about this request from the CEO for months but didn’t think to discuss it with the developers. And because of the delay requirements weren’t developed properly and everyone will be scrambling to understand this huge problem in a very short time and will be delivering their poorest work because they aren’t getting enough sleep.&lt;/p&gt;

&lt;p&gt;Okay, rant over.&lt;/p&gt;
&lt;h4&gt;The Solution&lt;/h4&gt;
&lt;p&gt;A sustainable pace in software development requires more than just time. Planning is just as crucial, but not just any kind of planning: smart planning &lt;strong&gt;&lt;em&gt;with the developers&lt;/em&gt;&lt;/strong&gt; who will be working on the feature. What constitutes smart planning? A careful consideration of the features you want, with feedback from developers taken into consideration.&lt;/p&gt;

&lt;p&gt;I’m going to borrow an analogy from a former boss. Imagine, if you will, a triangle. Each point represents an aspect of software development in practice. One represents Time, another represents Features, and the last represents Quality. As with most things in life, you can’t have everything, you must choose which two points are most valuable to you. By imposing a deadline by which all of these features must be finished you are choosing Time and Features and neglecting &lt;del&gt;arguably&lt;/del&gt; the most important element on our diagram.&lt;/p&gt;

&lt;p&gt;A more sensible approach is to choose one of the other two options. If you choose Time and Quality, you’ll have to prioritize which features are most important (which probably means reducing scope and scaling back) and choose only what the developers are comfortable committing to complete within the allotted time. This is the option I would opt for most of the time.&lt;/p&gt;

&lt;p&gt;You may also choose Quality and Features which means it will get done when it get’s done, but you’ll know that what you have is the right product with good quality. The drawback I see in this is that by ignoring the time element you often (though not always) lose valuable feedback you get through iterative designs.&lt;/p&gt;
&lt;h3&gt;Am I quixotic?&lt;/h3&gt;
&lt;p&gt;Probably. I’m that way a lot. But I before you dismiss my musings I hope you will consider the value each developer brings. In my next post in this series I’ll address this. As always, post your thoughts below.&lt;/p&gt;
</description>
        <pubDate>Tue, 26 May 2015 08:00:13 +0000</pubDate>
        <link>http://tuesdaydeveloper.com/2015/05/26/the-cause-of-poor-code.html</link>
        <guid isPermaLink="true">http://tuesdaydeveloper.com/2015/05/26/the-cause-of-poor-code.html</guid>
        
        
      </item>
    
      <item>
        <title>A Better Way</title>
        <description>&lt;p&gt;Since the onset of my programming career it seemed to me that there must be a better way.&lt;/p&gt;

&lt;p&gt;In college I really enjoyed learning how to “think like a computer” (as one teacher put it). I got very good at dissecting each problem and tuning the gears and syntax of a language to make the programs work well. I felt destined to be a great coder and I was excited for the destiny that surely awaited.&lt;/p&gt;

&lt;p&gt;In the more advanced courses, shortly before graduation, I felt a resistance to some of the more complex patterns and practices, but I didn’t question them because I knew that I was just some silly undergraduate with no real experience—and besides, all I needed was time to understand the new practices that seemed a bit odd and I would be able to master those too. Despite my hesitance, I did very well in my classes. I really enjoyed my professors and it seemed that they were impressed by me as well.&lt;/p&gt;

&lt;p&gt;And then I graduated.&lt;/p&gt;

&lt;p&gt;I had a rude awakening in my first job when I realized how little I really knew and when I discovered how very &lt;em&gt;wrong&lt;/em&gt; the code I inherited and was expected to curate was.&lt;/p&gt;

&lt;p&gt;In each job I’ve begun I’ve made the same realizations—I don’t know enough and I’ll be working on some ugly code.&lt;/p&gt;

&lt;p&gt;I’ve attempted to address the first issue, and I continue to educate myself continually (as well as can be expected for a full-time worker who also has a two-year-old).&lt;/p&gt;

&lt;p&gt;As for the second point, however, I’m almost beginning to wonder if the software project exists that I wouldn’t classify as abysmal in its architecture, organization, and/or general messed-up-ness. Perhaps the odds have been stacked against me and I’ve just been unlucky with the jobs that I’ve had, but the way other programmers talk there are even worse faits than the piles of spaghetti code I’ve worked on.&lt;/p&gt;

&lt;p&gt;This isn’t to say that all the code I’ve worked on has been completely bad, there was certainly strong points in each code base that I’ve worked on. It’s also certainly true that I’m not nearly as experienced as other software engineers and perhaps I wouldn’t recognize good code if I saw it. But, well, I’m pretty arrogant and I don’t think that’s the case.&lt;/p&gt;

&lt;p&gt;I’m starting to wonder if what Tolstoy says of &lt;a href=&quot;http://www.goodreads.com/quotes/7142-all-happy-families-are-alike-each-unhappy-family-is-unhappy&quot; target=&quot;_blank&quot;&gt;happy and unhappy families&lt;/a&gt; can be said of software as well:&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;All good code is alike; all bad code is bad in its own way.&lt;/p&gt;
&lt;p&gt;But one thing bothers me more than anything else: What is good code?&lt;/p&gt;

&lt;p&gt;Is there one true way to code that is superior to all other methods? Is there a language that is better than all the rest? If there is a better way to organize, write, create, and author code; does anyone know what it is?&lt;/p&gt;

&lt;p&gt;To be sure there are a lot of opinions out there. I’m not interested in opinions! I want facts. Something that can be proven and is measurable. There is a litmus test for this better way:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Are fewer bugs recorded?&lt;/li&gt;
	&lt;li&gt;Is the code easy to follow and understand?&lt;/li&gt;
	&lt;li&gt;Is there added complexity and overhead required that isn't necessary (rather than the pomp and circumstance you see with a good number of frameworks)?&lt;/li&gt;
	&lt;li&gt;How easy it is to respond to errors?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I don’t purport to have all the answers, I may be close to understanding some of them, but there is also the danger of finding more questions along the way….&lt;/p&gt;

&lt;p&gt;(This is the first post in a series: &lt;a href=&quot;/tag/a-better-way/&quot;&gt;A Better Way&lt;/a&gt;.)&lt;/p&gt;
</description>
        <pubDate>Tue, 12 May 2015 08:00:29 +0000</pubDate>
        <link>http://tuesdaydeveloper.com/2015/05/12/a-better-way.html</link>
        <guid isPermaLink="true">http://tuesdaydeveloper.com/2015/05/12/a-better-way.html</guid>
        
        
      </item>
    
      <item>
        <title>An Apologist's Defense of Trunk-based Development</title>
        <description>&lt;p&gt;There are two prevailing thoughts about source code management in contemporary software development with multi-member teams: trunk-based development and the feature branch model (or pull-request model). Looking at GitHub alone will surly lead you to believe that the only way to develop with a distributed source control system is using the pull-request model, but then there are technology pundits out there who opine that the only way to use git (or one of its relatives) is using the trunk based development model.&lt;/p&gt;

&lt;p&gt;This disparity (the masses using one model, but the role-models prescribing another) has understandably led to confusion in the tech industry. After reading &lt;a href=&quot;http://martinfowler.com/bliki/FeatureBranch.html&quot;&gt;Martin Fowler’s excellent description of Trunk Based Development&lt;/a&gt; (which he refers to as it’s more classical, but now overloaded, terminology: Continuous Integration) I found a few bloggers that didn’t like Martin Fowler’s suggestions. I’m going to address the article found &lt;a href=&quot;http://web.archive.org/web/20110721063430/http://jamesmckay.net/2011/07/why-does-martin-fowler-not-understand-feature-branches/&quot;&gt;here&lt;/a&gt; by James McKay (whom I will refer to as JM). I will attempt to assuage some of their concerns and answer some of the questions they have in this post.&lt;/p&gt;
&lt;h3&gt;Continuous Integration &lt;em&gt;is&lt;/em&gt; At Odds With Feature Branching&lt;/h3&gt;
&lt;p&gt;The first point that JM brings up is, “[Martin Fowler and Mike Mason] are saying that Feature Branching is incompatible with Continuous Integration.” I believe that the source of the confusion here is simply a case of semantics and history.&lt;/p&gt;

&lt;p&gt;Continuous Integration (as I eluded to previously) has multiple meanings today. The history of the term is described very well on &lt;a href=&quot;http://en.wikipedia.org/wiki/Continuous_integration&quot;&gt;Wikipedia&lt;/a&gt;, but it would do well to quote the opening line, “&lt;b&gt;Continuous integration&lt;/b&gt; (&lt;b&gt;CI&lt;/b&gt;) is the practice, in software engineering, of merging all developer working copies with a shared mainline several times a day.” As you can see its original meaning had nothing to do with build servers, but various vendors coopted the term (quite successfully) and  the original meaning is lost on some developers. Continuous Integration originally meant just that—integrating continuously. Integrating all the new code you wrote as frequently as you can with what is the latest code on a single branch. Everyone has the same version of the latest code. With Feature Branching you don’t share this promise. Everyone may have the latest code from a shared branch, but they also have their own dirty little secrets which none of the other branches share.&lt;/p&gt;

&lt;p&gt;Git and Mercurial often show a representation of a commit history something like this for feature branches:&lt;a href=&quot;/uploads/2015/05/feature-branches.png&quot;&gt;
&lt;img class=&quot;alignleft size-medium wp-image-730&quot; src=&quot;/uploads/2015/05/feature-branches-300x120.png&quot; alt=&quot;feature-branches&quot; width=&quot;300&quot; height=&quot;120&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The blue branch in the middle is the shared, common, dev, develop, whatever-you-want-to-call-it branch. The plan is to release whatever is on the blue branch. The red and yellow branches are feature branches that have branched off of the blue branch. Unfortunately this image is misleading. The red and yellow branches may be merging frequently with the blue branch, but they aren’t as close to each other as they may seem. The red and yellow branches are actually drifting further and further apart. Something like the next image:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/uploads/2015/05/feature-branches-reality.png&quot;&gt;&lt;img class=&quot;alignleft size-medium wp-image-729&quot; src=&quot;/uploads/2015/05/feature-branches-reality-300x233.png&quot; alt=&quot;feature-branches-reality&quot; width=&quot;300&quot; height=&quot;233&quot; /&gt;&lt;/a&gt;The blue branch, which is still getting commits (presumably from other branches) is still the same distance from both red and yellow, but red and yellow are much further apart., The more code that is added to red but not to yellow or to yellow but not to red the more different they become. The longer time goes without merging the code from red and yellow together (as well as any other feature branches) the further apart they two branches will drift, even if they are continually merging with blue.&lt;/p&gt;

&lt;p&gt;This leads us to a natural question about what happens when one of these branches merges with the shared blue branch. I’m glad you asked, I’ve got an image for that:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/uploads/2015/05/feature-branch-after-merge.png&quot;&gt;&lt;img class=&quot;alignleft size-medium wp-image-728&quot; src=&quot;/uploads/2015/05/feature-branch-after-merge-300x260.png&quot; alt=&quot;feature-branch-after-merge&quot; width=&quot;300&quot; height=&quot;260&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the third image you see that the yellow branch is nowhere near where the blue branch is anymore. In fact it is further from blue than when it started because now the blue branch is also the red branch and so yellow is actually as far away from its parent as it was from the red branch.&lt;/p&gt;

&lt;p&gt;This will remain the case until a merge occurs which will likely cause a &lt;em&gt;huge&lt;/em&gt; merge conflict and while merge conflicts would happen even when using trunk based development, they occur are more regulated and more manageable intervals (more on that later).&lt;/p&gt;

&lt;p&gt;Obviously this is an image and I haven’t calculated the actual difference between the red and yellow branches, theoretically this could be done with an algorithm that tracked differences, but the point is clear: when using feature branches you are often in danger of working on a branch that is very different from the other feature branches and when one of them merges before your branch merges then you will have to deal with the problem of finding out how to merge the two very different code bases together.&lt;/p&gt;

&lt;p&gt;The problem highlighted is known as &lt;em&gt;delayed integration&lt;/em&gt; which, just like it sounds, is exactly the opposite of Continuous Integration and means that the developers involved have waited to integrate their code with others’ code. That’s why feature branches are at odds with Continuous Integration, because they are nothing alike.&lt;/p&gt;
&lt;h3&gt;Merging Isn't So Bad&lt;/h3&gt;
&lt;p&gt;JM declares that they didn’t feel that merging was so bad (maybe not is so many words). They’re right. But it is dangerous, and in more ways than one. In fact there are three ways that merging is dangerous. The first is obvious, the developer preforming the merge may make a mistake. Maybe they misunderstood the other developer’s code or they could have forgotten exactly what that piece of code was supposed to do. It’s true that this is a problem that can be retroactively rectified, but it’s still inconvenient.&lt;/p&gt;

&lt;p&gt;The second is a little less obvious and doesn’t have anything to do with the actual merge process, but in the fact that merging must wait. The problem arrises when you have to wait to share code! Just the other day I overheard two developers talking. One of them needed some code that the other had written, but they were working in two different branches. They spent probably ten minutes thinking of ways to get Git to share parts of one branch with the other, but not merging the whole branch.&lt;/p&gt;

&lt;p&gt;The last way that merging is dangerous is because it gets more difficult with time. I like to think of it as gum on a sidewalk. If someone spits gum on the sidewalk (it wasn’t you, of course, because it is a nasty habit) it’s really quite easy to get it off the ground and into a trash bin. But if you wait a week, chances are that it has been stepped on and trampled and it will take a long time to get it off (unless you have a high-powered presser washer handy).&lt;/p&gt;

&lt;p&gt;Merging little changes (like you do with trunk based development) is usually painless, but the longer you let changes go without merging them the greater the chance that you code will be more difficult to merge. This is one of the best features of Trunk Based Development: small merges, frequently.&lt;/p&gt;
&lt;h3&gt;Feature Toggles&lt;/h3&gt;
&lt;p&gt;There seems to be a lot of fear about feature toggles. Whether it done using branch by abstraction or permissions or some other method it’s basically a method to not call new code until the time comes when it is ready to turn them on. JM feels that feature toggling is actually more dangerous than keeping code completely isolated until it is ready to be used and I respect this fear. It’s true that there is a small amount of risk involved when toggling a feature that isn’t ready yet. But I want to point out a misunderstanding that he has and a benefit that feature toggles have that you wouldn’t get when using feature branches.&lt;/p&gt;

&lt;p&gt;First, James McKay says that feature branches is releasing code that is untested. This is untrue. We must keep in mind that trunk based development isn’t just a pattern for the repository—it is a pattern for the way we code as well. In trunk based development one never pushes code that hasn’t passed every unit test and doesn’t have unit test written for it as well. If you are careful, end users should never be running the code that isn’t ready, but if by some small chance they do it should be tested. (I don’t have time to get into the &lt;a href=&quot;http://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;classic unit tests vs the mockist approach&lt;/a&gt;, but there are differences of opinion about that in the software development world too. I believe that if unit tests are written using the classic approach, which is a manner that test more consistently with how a user may be using or misusing your system, then those tests will be more than adequate at preventing bugs in feature toggled software without manual tests of any kind.)&lt;/p&gt;

&lt;p&gt;The other benefit to using feature toggles comes into play when everything is working as designed, but you want to turn a feature off for a business reason. Maybe you are using a social network’s Oauth 2 authentication to login to your site, but then a competitor acquires them and you want to turn off everything in your site associated with them. If you’ve been using feature toggles this becomes a simple matter of reenabling the toggle that was in place—if not, you may need to go in and manually remove all traces by hand (introducing the chance for bugs and errors that wouldn’t have happened if you used a configuration or abstraction to keep a feature from being released). Of course this means whatever mechanism you are using to do your feature toggles can be reenabled and hasn’t been removed, but chances are good that it’s easier to reenable a feature toggle than to remove and replace code by hand.&lt;/p&gt;
&lt;h3&gt;Whatever Merge Goes&lt;/h3&gt;
&lt;p&gt;I’ve compared and contrasted two version control models, Trunk Based Development and Feature Branches. There is, however, a third option that gets some usage. Unfortunately this model sometimes gets confused with Trunk Based Development, but the two are very different. There isn’t really an official name for it, but I like to call it Whatever Merge Goes meaning a haphazard, non-regulated method for software version control.&lt;/p&gt;

&lt;p&gt;It’s confused with Trunk Based Development, because there is usually only one shared branch. The difference is that the trunk branch is treated carelessly. Developers aren’t required to run unit tests before committing and pushing code or to even write them. Stories are not polished before developers are expected to work with them (and the developers almost never helped define them) and so there is real risk that the features committed to for a coding cycle may only get half-way done by the deadline and won’t be able to be removed which will result in a traffic jam of last minute changes and half-tested code.&lt;/p&gt;

&lt;p&gt;Please don’t confuse a team working on a single shared branch with Trunk Based Development. Trunk Based Development requires discipline and diligence. Adequate tests, discipline to run them and verify the build won’t break, and frequent pushes (not just when your code if &lt;em&gt;finished&lt;/em&gt; but when it’s in a stable state) and pulls are all a vital part of Trunk Based Development. Between having no process and having Feature Branches, I’d choose Feature Branches too even though that will only go so far to improve the situation.&lt;/p&gt;
&lt;h3&gt;When to Choose Feature Branches&lt;/h3&gt;
&lt;p&gt;In all professionally developed projects I would use Trunk Based Development. With personal projects (where you or a small group of friends are working on an application) I’d use Trunk Based Development. The only time I would consider branching is when I was working with an open source project and didn’t know if I could trust the other developers contributing.&lt;/p&gt;

&lt;p&gt;For an excellent resource regarding Trunk Based Development refer to &lt;a href=&quot;http://paulhammant.com&quot;&gt;Paul Hammant’s blog&lt;/a&gt;, he has several articles talking about what Trunk Based Development is, why it’s better, and about how companies like Facebook and Google use Trunk Based Development.&lt;/p&gt;

&lt;div class=&quot;archived comments&quot;&gt;

&lt;div class=&quot;comment&quot;&gt;&lt;blockquote&gt;First, James McKay says that feature branches is releasing code that is untested.&lt;/blockquote&gt;

I think you meant to say &quot;feature toggles&quot; here.

While I'm suggesting edits, &quot;eluded&quot; should be &quot;alluded&quot;, &quot;they two&quot; should be &quot;the two&quot;, &quot;not is so&quot; —&amp;gt; &quot;not in so&quot;, &quot;you code&quot; —&amp;gt; &quot;your code&quot;, &quot;presser&quot; —&amp;gt; &quot;pressure&quot;, and &quot;Oauth 2&quot; —&amp;gt; something that actually works.  (You should take heart in the fact that the only first draft I've seen of Martin Fowler's was littered with typos and omitted words.)

I, too, am dismayed at the abuse of the term &quot;Continuous Integration&quot;: &quot;Of course we do Continuous Integration: we have our Continuous Integration server all set up, with a build for every feature branch!  It's especially useful at the end of the month when we integrate all the feature branches.&quot;

Another pitfall I've seen is teams implementing &quot;Continuous Integration&quot; by merging &lt;i&gt;from&lt;/i&gt; master (or &quot;trunk&quot; or &quot;main&quot; or &quot;mainline&quot;) multiple times a day—until they all realize this is pointless, because nobody's merging anything &lt;i&gt;into&lt;/i&gt; master until the last couple days of the sprint.  Maybe &quot;trunk-based development&quot; would be a useful label for avoiding this situation.  &lt;div class=&quot;by&quot;&gt;George Paci on 2015-08-29 09:40:47.0  &lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Mon, 11 May 2015 15:45:26 +0000</pubDate>
        <link>http://tuesdaydeveloper.com/2015/05/11/an-apologists-defense-of-trunk-based-development.html</link>
        <guid isPermaLink="true">http://tuesdaydeveloper.com/2015/05/11/an-apologists-defense-of-trunk-based-development.html</guid>
        
        
      </item>
    
      <item>
        <title>Angular Dependency Injection</title>
        <description>&lt;p&gt;I just spent two awesome days at &lt;a href=&quot;http://ng-conf.org&quot;&gt;ng-conf 2014&lt;/a&gt; where were presented with a challenge to improve upon the already &lt;em&gt;awesome&lt;/em&gt; Angular dependency injection. At first I didn’t really have any ideas. “The only way to improve the DI framework would require interfaces,” I thought. And I left it at that.&lt;/p&gt;

&lt;p&gt;My subconscious mind, however, kept working on it and I woke up at five this morning with a few ideas. I admit that this solution needs some improvement, but I thought I’d at least write it down and see what comes of it.&lt;/p&gt;

&lt;p&gt;One of the few weaknesses that Angular has in its dependency framework is because JavaScript lacks interfaces. This doesn’t mean however that Angular couldn’t build an interface system. I’m not sure if these ideas could be used without a framework like Angular, so I write this document with the understanding that it would naturally fit into Angular.&lt;/p&gt;

&lt;p&gt;Before I begin, I should explain a little about how I personally use Angular, and more importantly, how the various pieces used in Angular come together to help the code stay organized. When I finally convinced my employer, to use Angular, the first thing we found is that it was very easy for everyone to have their own way to structure their code. It is for this reason that I came up with a coding standard that we now currently use.&lt;/p&gt;

&lt;p&gt;There is, obviously, nothing in Angular that enforces this standard and I’ve seen a lot of good code that does it differently, but this is what makes most sense to me.&lt;/p&gt;

&lt;p&gt;As you know, under the hood services and factories are the same thing in Angular. While I see no reason for this to change, I try to keep them and their purposes logically separated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Factories:&lt;/strong&gt;
A factory is used only when dealing with things that need to be created or saved. In general this means that they use $resource (or sometimes $http) to interact with our API. Controllers never directly interact with a factory, rather they are always used by a service. Factories always have the postfix, “Factory”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Services:&lt;/strong&gt;
A service is used to keep logic for a certain thing together. This helps with code reuse and to keep the size of a controller to a minimum. Services are used directly from controllers and other services. Often services use factories to get or save off data. Services are always prefixed with a dollar sign and a two letter abbreviation for the company or project it is used for. (Example: If I’m building a task app called Task App a users service may be named: $taUsers.&lt;/p&gt;

&lt;p&gt;With that out of the way, I’ll explain what I think could be a good idea for Angular. I hope that there are others who can improve upon this because it has some spots that are a bit clunky.&lt;/p&gt;

&lt;p&gt;I consider myself pretty new in the software engineering world, but when I think of dependency injection I think of interfaces. Most of my knowledge about DI is colored by the C# dependency injection framework: Windsor. The general principle that Angular lacks when it comes to dependency injection is that there can be more than one dependency that meets the requirements of the dependency. The particular implementation used is usually chosen at runtime based on the DI frameworks configuration. The only problem is that to do this correctly: there really needs to be interfaces, or something that acts like an interface, in JavaScript. I’m not sure what the best practice would be for declaring the members of an interface, but this is one idea. (Using ECMAScript 5.)&lt;/p&gt;

&lt;p&gt;&lt;b&gt;For “Pet Application” this would be used to create an interface.&lt;/b&gt;&lt;/p&gt;
&lt;pre lang=&quot;javascript&quot; line=&quot;1&quot;&gt;app.interface('iAnimalService', {
  species: angular.STRING,
  commonName: angular.STRING,
  numberOfLegs: angular.NUMBER,
  speak: function(duration){}
});&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;Implementing the interface.&lt;/b&gt;&lt;/p&gt;
&lt;pre lang=&quot;javascript&quot; line=&quot;10&quot;&gt;app.service('$paDog', function(){
  angular.implements('iAnimalService', this);//will throw an error if the requirements are not met

  this.species = “Canis lupus”;
  this.speak = function(duration){
    //…
  }
  //etc.
});&lt;/pre&gt;
&lt;p&gt;You can see that the $paDog service implements the iAnimalService interface and that any derivation from the contract will cause an error to be thrown.&lt;/p&gt;

&lt;p&gt;I hope that this was helpful. I would love to hear feedback on this and how it could be improved or thoughts that others have.&lt;/p&gt;

&lt;div class=&quot;archived comments&quot;&gt;

&lt;div class=&quot;comment&quot;&gt;Hey great article, I just wanted to mention you have a duplicate paragraph .

&quot;&lt;b&gt;There is, obviously, nothing in Angular that enforces this standard and I’ve seen a lot of good code that does it differently, but this is what makes most sense to me.&lt;/b&gt;&quot;  &lt;div class=&quot;by&quot;&gt;Andrew Del Prete on 2014-01-22 12:02:21.0  &lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Sat, 18 Jan 2014 08:38:11 +0000</pubDate>
        <link>http://tuesdaydeveloper.com/2014/01/18/angular-dependency-injection.html</link>
        <guid isPermaLink="true">http://tuesdaydeveloper.com/2014/01/18/angular-dependency-injection.html</guid>
        
        
      </item>
    
  </channel>
</rss>
