<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Alexander Oloo</title>
    <description>The latest articles on Forem by Alexander Oloo (@alekcz).</description>
    <link>https://forem.com/alekcz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F287085%2F1988d83a-4abc-496e-8fd6-15494a8c5221.png</url>
      <title>Forem: Alexander Oloo</title>
      <link>https://forem.com/alekcz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/alekcz"/>
    <language>en</language>
    <item>
      <title>From Developer to Design Director: 40 books</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Sun, 16 Aug 2020 04:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/from-developer-to-design-director-40-books-bb6</link>
      <guid>https://forem.com/alekcz/from-developer-to-design-director-40-books-bb6</guid>
      <description>&lt;p&gt;Circa 2016 I started my journey into the land of experience design. The journey from frontend dev to design director has been one heck of adventure. I’ve been extremely lucky to have had some excellent mentors, managers, and sponsors along the way. This post is not about them, but rather the books that accompanied me along the way.&lt;/p&gt;

&lt;p&gt;It all started when Phil threw down the gauntlet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s1BaV3HU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://alexanderoloo.com/images/blog/reading-list.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s1BaV3HU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://alexanderoloo.com/images/blog/reading-list.png" alt="Phil recommending some books"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Needless to say, I didn’t finish them all in a year. And I still haven’t read them all. But it was the beginning of a great reading habit. If you’re not a reader (or listener) yet, I can’t recommend it enough. Here’s a list of the books I’ve read on my journey. They’ve all been been quite value in my career and development.&lt;/p&gt;

&lt;p&gt;One last thing before the list. It’s a long list and will take you longer to read than you expect. You won’t remember everything you read. Some will be hard to read. You’ll get tired of reading. And feel like you’re not growing. All those things are okay. In the words of Josemaria Escriva:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Don’t forget that, on earth, every big thing has had a small beginning. What is born big is monstrous and dies.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Happy reading. Happy learning.&lt;/p&gt;

&lt;h3&gt;
  
  
  The List
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Becoming a better leader
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The Managers Path&lt;/li&gt;
&lt;li&gt;The Five Dysfunctions of a team&lt;/li&gt;
&lt;li&gt;Creativity Inc&lt;/li&gt;
&lt;li&gt;The Three Signs of a Miserable Job&lt;/li&gt;
&lt;li&gt;The Hard Thing about Hard Things&lt;/li&gt;
&lt;li&gt;Multipliers&lt;/li&gt;
&lt;li&gt;What You Do Is Who You are&lt;/li&gt;
&lt;li&gt;Never Split the Difference&lt;/li&gt;
&lt;li&gt;Non-violent communication&lt;/li&gt;
&lt;li&gt;The Art of War&lt;/li&gt;
&lt;li&gt;What to do when you become the boss&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Expanding your thinking
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Predictably Irrational&lt;/li&gt;
&lt;li&gt;Thinking in Bets&lt;/li&gt;
&lt;li&gt;Misbehaving&lt;/li&gt;
&lt;li&gt;Thinking, Fast and Slow&lt;/li&gt;
&lt;li&gt;Algorithms to Live By&lt;/li&gt;
&lt;li&gt;Interior Freedom&lt;/li&gt;
&lt;li&gt;Originals&lt;/li&gt;
&lt;li&gt;How to Get People to Do Stuff&lt;/li&gt;
&lt;li&gt;12 Rules for Life&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Supercharging your UX
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;About Face&lt;/li&gt;
&lt;li&gt;How to make Sense of any mess&lt;/li&gt;
&lt;li&gt;Don’t Make me think&lt;/li&gt;
&lt;li&gt;Lean UX&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Designing better products
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Zero to One&lt;/li&gt;
&lt;li&gt;Competing Against Luck&lt;/li&gt;
&lt;li&gt;Inspired&lt;/li&gt;
&lt;li&gt;Hooked: How to Build Habit forming products&lt;/li&gt;
&lt;li&gt;The Lean Startup&lt;/li&gt;
&lt;li&gt;Lean vs Agile vs Design Thinking&lt;/li&gt;
&lt;li&gt;The Service Startup&lt;/li&gt;
&lt;li&gt;The Lean enterprise&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Shipping quality products and software
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The Phoenix Project&lt;/li&gt;
&lt;li&gt;The Unicorn Project&lt;/li&gt;
&lt;li&gt;Accelerate: Building and Scaling High Performing Teams.&lt;/li&gt;
&lt;li&gt;Making work Visible&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Telling better stories
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Ted Talks&lt;/li&gt;
&lt;li&gt;Story&lt;/li&gt;
&lt;li&gt;Creating Character Arcs&lt;/li&gt;
&lt;li&gt;The Silmarillion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/Wp0ZtQjgViqR2/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/Wp0ZtQjgViqR2/giphy.gif" alt="Harley reading and drinking espresso"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

</description>
      <category>design</category>
      <category>books</category>
      <category>leadership</category>
      <category>ux</category>
    </item>
    <item>
      <title>Loading Google Credentials without .json</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Fri, 31 Jan 2020 04:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/loading-google-credentials-without-json-2oip</link>
      <guid>https://forem.com/alekcz/loading-google-credentials-without-json-2oip</guid>
      <description>&lt;p&gt;I primarily use heroku to run my applications and Travis for CI/CD. I’m also currently giving Github Actions a try. So what do all those have in common? Well, for starters they have generous free tiers, but more importantly they’re not in the Google Cloud. Google cloud has some really nifty capabilities and so I end up using them pretty often. That’s where my problem started.&lt;/p&gt;

&lt;p&gt;When you want to authenticate your application from outside the Google Cloud you need to read in a &lt;code&gt;.json&lt;/code&gt; file that contains the service account information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="n"&gt;credentialsPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/home/user/Downloads/[FILE_NAME].json"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_APPLICATION_CREDENTIALS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/home/user/Downloads/[FILE_NAME].json"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So we basically need to get this &lt;code&gt;.json&lt;/code&gt; file into all our CI/CD pipelines and our application servers. Obviously we can’t store the credentials in &lt;code&gt;git&lt;/code&gt; so we need to encrypt and upload the file. Admin!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/alekcz/google-credentials"&gt;alekcz/google-credentials&lt;/a&gt; solves exactly this problem. Your clojure app can now load credentials from an environment variable using &lt;code&gt;alekcz/google-credentials&lt;/code&gt;.You need not keep that super secret &lt;code&gt;.json&lt;/code&gt; file anymore. Copy its contents into the environment and delete the file!&lt;/p&gt;

&lt;p&gt;And there you go. Nothing but net.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/UYlu2EDUdiVl6/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/UYlu2EDUdiVl6/giphy.gif" alt="Kobe!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;P.S. Rest in peace Kobe.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>gcloud</category>
      <category>ci</category>
      <category>cd</category>
    </item>
    <item>
      <title>Fun with Clojure maps</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Mon, 09 Dec 2019 05:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/fun-with-clojure-maps-3lid</link>
      <guid>https://forem.com/alekcz/fun-with-clojure-maps-3lid</guid>
      <description>&lt;p&gt;There was a time where I was working exclusively in clojure and using SSR for the frontend. It was a peaceful time. But alas peace doesn’t last for ever. And then I picked up a new full stack project. A project building a SPA.&lt;/p&gt;

&lt;p&gt;And JSON said to me: &lt;em&gt;“Peace has cost you your strength. Victory has defeated you”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The hastle of parsing json Node was all too fresh in my memory. Would Clojure be different?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"link-profiles"&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
            &lt;/span&gt;&lt;span class="no"&gt;:data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"alekcz"&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
                    &lt;/span&gt;&lt;span class="no"&gt;:social&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:github&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"https://github.com/alekcz"&lt;/span&gt;&lt;span class="w"&gt; 
                              &lt;/span&gt;&lt;span class="no"&gt;:twitter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"https://twitter.com/alekcz"&lt;/span&gt;&lt;span class="p"&gt;}}})&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first time I had to parse a json request I hit a quick google. I was still quite new to Clojure so most problems involved a quick google. And voilà. &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LDN49cHB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://alexanderoloo.com/images/blog/get.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LDN49cHB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://alexanderoloo.com/images/blog/get.png" alt='Getting data from within a map"' title="Getting data from within a map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I tried &lt;code&gt;get&lt;/code&gt;. And it was ridiculous&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:social&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:twitter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And when something is unwieldy in Clojure there’s probably a more elegant way of doing it. You just need to be willing to look beyond the first google result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:social&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:twitter&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Oh isn’t that nice. You gotta love the elegance. To be honest I thought that was as good as it got, until I stumbled across this &lt;a href="https://stackoverflow.com/a/7035984"&gt;gem&lt;/a&gt;. Turns out you can access data in a map using key like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; {:user "alekcz", :social {:github "alekcz", :twitter "alekcz"}}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; and doing this didn't crash anything.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; nil&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It was like magic. Immediately it made me think of the &lt;a href="https://alexanderoloo.com/blog/2019/12/08/clojures-thread-first-macro.html"&gt;thread-first macro&lt;/a&gt;. Maybe? Just maybe we could? Was it too good to be true? Surely not?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:social&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:twitter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; "https://twitter.com/alekcz"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Sublime.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post is part of the &lt;a href="https://alexanderoloo.com/blog/2019/12/01/advent-of-parens.html"&gt;“Advent of Parens”&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>maps</category>
      <category>threadfirst</category>
      <category>day8</category>
    </item>
    <item>
      <title>Clojure’s thread-first macro: -&gt;</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Sun, 08 Dec 2019 07:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/clojure-s-thread-first-macro-337g</link>
      <guid>https://forem.com/alekcz/clojure-s-thread-first-macro-337g</guid>
      <description>&lt;p&gt;Don’t you just hate functions with names that you can’t pronounce. I mean how do you pronounce &lt;code&gt;-&amp;gt;&lt;/code&gt; ? On top of that, its name is not consistent across languages so learning it once is not a guarantee that you’ll know its name in another programming language.&lt;/p&gt;

&lt;p&gt;In Clojure this, &lt;code&gt;-&amp;gt;&lt;/code&gt;, is the thread-first macro. You’re welcome.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s"&gt;"Threads the expr through the forms. Inserts x as the
second item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
second item in second form, etc."&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  A super practical everyday example
&lt;/h3&gt;

&lt;p&gt;To help us illustrate how the thread-first macro works we need a few functions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="c1"&gt;; let's set everything up&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"wheat-seed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;farm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"-&amp;gt;planted"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;harvest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;plant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;farm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"-&amp;gt;harvested"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;grind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;grain&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;grain&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"-&amp;gt;ground"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;prepare-dough&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;flour&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sugar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;olive-oil&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flour&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"-&amp;gt;prepared-dough"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;   
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;make-base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dough&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dough&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"-&amp;gt;made-base"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;   
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add-toppings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tomato&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cheese&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;meat&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"-&amp;gt;added-toppings"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bake&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dough&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;oven&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dough&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"-&amp;gt;baked"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enjoy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pizza&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pizza&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"-&amp;gt;enjoyed-macro-pizza"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now let’s get threading!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="c1"&gt;;Now lets make a macro pizza&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;plant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"far-field"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Old McDonald's Farm"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;harvest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Old McDonald's Farm"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;grind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"stone-mill"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;prepare-dough&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"sea-salt"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"white-sugar"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"ev-olive-oil"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;make-base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;add-toppings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"rosa-tomatoes"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"mozzarella"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"ham"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;bake&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"stone oven"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;enjoy&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You’ll notice that each function in our pizza maker has one less argument than in its function definition. The first argument is handled by thread-first macro. The thread-first macro takes the output of &lt;code&gt;ws&lt;/code&gt; and makes it the first argument of &lt;code&gt;plant&lt;/code&gt; and makes the output &lt;code&gt;plant&lt;/code&gt; the first argumemt of &lt;code&gt;harvest&lt;/code&gt;. In other words it does this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;harvest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;plant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"far-field"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Old McDonald's Farm"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Old McDonald's Farm"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; 

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And hence its name. It threads previous output as the &lt;strong&gt;first&lt;/strong&gt; argument of the next function and continues doing so until it’s done.&lt;/p&gt;

&lt;p&gt;The true benefit of the thread-first macro is that it can make code easier to read. You can do your future self a huge favour by using the thread-first macro. Using this macro coupled with naming your functions sensibly makes for code that is a pleasure to read and maintain.&lt;/p&gt;

&lt;p&gt;Happy threading!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post is part of the &lt;a href="https://alexanderoloo.com/blog/2019/12/01/advent-of-parens.html"&gt;"Advent of Parens"&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>threadfirst</category>
      <category>day8</category>
    </item>
    <item>
      <title>Clojure shootout: keep vs filter</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Sat, 07 Dec 2019 07:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/clojure-shootout-keep-vs-filter-10pi</link>
      <guid>https://forem.com/alekcz/clojure-shootout-keep-vs-filter-10pi</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;a href="https://www.youtube.com/watch?v=_5Zik3jak3A"&gt;Oh no, it happened again&lt;/a&gt;&lt;/em&gt; &lt;br&gt;
&lt;em&gt;it’s time to filter or keep&lt;/em&gt;&lt;br&gt;
&lt;em&gt;you ponder for hours it’s so&lt;/em&gt;&lt;br&gt;
&lt;em&gt;you don’t know which way to go&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It doesn’t really help that there are two clojure functions that do exactly the same thing. Isn’t that PHPs trademark? I’ve been burned by these twins. One of them is evil. One of them is good. Which is which?&lt;/p&gt;
&lt;h3&gt;
  
  
  Keep docs
&lt;/h3&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;keep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;keep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coll&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s"&gt;"Returns a lazy sequence of the non-nil results of (f item). Note,
this means false return values will be included. f must be free of
side-effects. Returns a transducer when no collection is provided."&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Filter docs
&lt;/h3&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pred&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pred&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;coll&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="s"&gt;"Returns a lazy sequence of the items in coll for which
(pred item) returns logical true. pred must be free of side-effects.
Returns a transducer when no collection is provided."&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;From the docs we can see they have the same function signature, they’re both lazy, both live in &lt;code&gt;clojure.core&lt;/code&gt;, they can both produce transducers, and both the applied functions must be free of side effects (yum, clojurey). But if you look a little closer there’s a gremlin waiting to hurt you…&lt;/p&gt;

&lt;p&gt;Let’s try keep the odd numbers less than 10.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;keep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;odd?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; (false true false true false true false true false true)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That’s not ideal. &lt;code&gt;keep&lt;/code&gt; told us which numbers to keep but didn’t give us the actual numbers. And this is where the gremlin lives. &lt;code&gt;keep&lt;/code&gt; will return the result of applying to &lt;code&gt;f&lt;/code&gt; to each element if and only if the result is not &lt;code&gt;nil&lt;/code&gt;. &lt;code&gt;f&lt;/code&gt; must then be written specifically to work as such. In others words you can’t reuse the transducer you’ve already written as is.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;keep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;odd?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; (false 1 false 3 false 5 false 7 false 9)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;; keep really needs that nil&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;keep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;odd?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; (1 3 5 7 9)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;; or more concisely (relying on the inner workings of if, eek)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;keep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;odd?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; (1 3 5 7 9)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And what does filter do? Exactly what you expect. And that, that is the right thing to do.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;odd?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; (1 3 5 7 9) &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; Yay!&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;No matter how whacky you get, it does what you expect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="c1"&gt;; you shouldn't do this (not a predicate)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;odd?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; (1 3 5 7 9)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;; and definitely not this (not a predicate)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;odd?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; (1 3 5 7 9)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;; and this is just plain odd (not a predicate)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;odd?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; (1 3 5 7 9)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Filter works even if your predicates are not predicates. Filter has your back either way. And when you’re building your confidence in a language, that’s important.&lt;/p&gt;

&lt;p&gt;Filter what you don’t need. Keeping them is just plain weird.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post is part of the &lt;a href="https://alexanderoloo.com/blog/2019/12/01/advent-of-parens.html"&gt;"Advent of Parens"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;* Predicates are functions that given a value return either true or false, based on their internal citeria&lt;/em&gt;&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>filter</category>
      <category>keep</category>
      <category>day7</category>
    </item>
    <item>
      <title>Gotcha! It’s the trailing slash</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Fri, 06 Dec 2019 07:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/gotcha-it-s-the-trailing-slash-53c5</link>
      <guid>https://forem.com/alekcz/gotcha-it-s-the-trailing-slash-53c5</guid>
      <description>&lt;p&gt;&lt;em&gt;You’ve discovered the &lt;a href="http://www.luminusweb.net/"&gt;Luminus framework&lt;/a&gt;. You’ve reached unparalleled levels of productivity. You can build a web app at the drop of a hat. You can’t believe no-one told you about this before. You’re life is perfect except for one small thing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Every now and then an existing route returns a 404. It doesn’t make sense. The error only occurs some of the time. Should that even be possible? You want to pull you hair out…&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GOTCHA! It’s the trailing slash!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Luminus relies on the awesome routing library by &lt;a href="https://github.com/metosin/reitit"&gt;reitit&lt;/a&gt;. And reitit uses exact route matching. So &lt;code&gt;/apply&lt;/code&gt; and &lt;code&gt;/apply/&lt;/code&gt; are two different routes. Therefore depending on how your end user enters the url, they may or may not get a 404.&lt;/p&gt;

&lt;p&gt;Here’s how I fixed it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mount/defstate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ring/routes&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;swagger-ui/create-swagger-ui-handler&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/swagger-ui"&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="no"&gt;:url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/api/swagger.json"&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="no"&gt;:config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:validator-url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ring/create-resource-handler&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrap-content-type&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrap-webjars&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;constantly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="c1"&gt;; Here is it is =&amp;gt; &lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ring/redirect-trailing-slash-handler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:method&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:strip&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="c1"&gt;;&amp;lt;= and you're good to go&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ring/create-default-handler&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can learn more about handling the trailing slash &lt;a href="https://cljdoc.org/d/metosin/reitit/0.3.10/doc/ring/slash-handler"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post is part of the &lt;a href="https://alexanderoloo.com/blog/2019/12/01/advent-of-parens.html"&gt;"Advent of Parens"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Today’s post is late courtesy of our wonderful electricity provider Eskom. Loadshedding is the best!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>luminus</category>
      <category>day6</category>
    </item>
    <item>
      <title>Destructuring keys in clojure</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Thu, 05 Dec 2019 07:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/destructuring-keys-in-clojure-2g6</link>
      <guid>https://forem.com/alekcz/destructuring-keys-in-clojure-2g6</guid>
      <description>&lt;p&gt;Oh, you think JSON is your ally? I do a lot work with JSON. So much so that my favourite library is a JSON parsing library (&lt;a href="https://github.com/dakrone/cheshire"&gt;cheshire&lt;/a&gt;). The most tedious thing about working wiht JSON is pulling keys out of JSON objects over and over again.&lt;/p&gt;

&lt;p&gt;Associative destructuring is the hero we need but don’t deserve. It’s syntactic sugar for extracting keys from an object in a way that makes code more readable. More readable code is more maintainable code. It’s made my life much easier.&lt;/p&gt;

&lt;p&gt;Given the following map, that was created by parsing a JSON object using &lt;a href="https://github.com/dakrone/cheshire"&gt;cheshire&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;json-object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:fname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Alexander"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:lname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Oloo"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:handle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"alekcz"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"ZA"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The standard approach to using data from within the map is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;twitter-link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;a href='https://twitter.com/"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:handle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"'&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:fname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;" (@"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:handle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;")&amp;lt;/a&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;twitter-link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;json-object&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; &amp;lt;a href='https://twitter.com/'&amp;gt;Alexander (@alekcz)&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But when we use associative destructuring we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;twitter-link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="no"&gt;:keys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;a href='https://twitter.com/"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"'&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;" (@"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;")&amp;lt;/a&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;twitter-link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;json-object&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;; =&amp;gt; &amp;lt;a href='https://twitter.com/'&amp;gt;Alexander (@alekcz)&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Isn’t that so much nicer? I think it is. It’s a pity I didn’t see transit until I was already a man.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post is part of the &lt;a href="https://alexanderoloo.com/blog/2019/12/01/advent-of-parens.html"&gt;"Advent of Parens"&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>destructuring</category>
      <category>day5</category>
    </item>
    <item>
      <title>My 5 favourite clojure libraries</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Wed, 04 Dec 2019 07:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/my-5-favourite-clojure-libraries-2gdl</link>
      <guid>https://forem.com/alekcz/my-5-favourite-clojure-libraries-2gdl</guid>
      <description>&lt;p&gt;In my travels I have collected a set of clojure libraries that I can rely on to help me solve problems effectively. These are my top 5.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/dakrone/cheshire"&gt;cheshire&lt;/a&gt; by &lt;a href="https://github.com/dakrone"&gt;@dakrone&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/http-kit/http-kit"&gt;http-kit&lt;/a&gt; by &lt;a href="https://github.com/shenfeng"&gt;@shenfeng&lt;/a&gt; and maintained by &lt;a href="https://github.com/ptaoussanis"&gt;@ptaoussanis&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ptaoussanis/nippy"&gt;nippy&lt;/a&gt; by &lt;a href="https://github.com/ptaoussanis"&gt;@ptaoussanis&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/overtone/at-at"&gt;at-at&lt;/a&gt; by &lt;a href="https://github.com/samaaron"&gt;@samaaron&lt;/a&gt;, &lt;a href="https://github.com/rosejn"&gt;@rosejn&lt;/a&gt;, and &lt;a href="https://github.com/michaelneale"&gt;@michaelneale&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/alekcz/charmander"&gt;charmander&lt;/a&gt; by &lt;a href="https://github.com/alekcz"&gt;@alekcz&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. cheshire
&lt;/h3&gt;

&lt;p&gt;cheshire is a library for &lt;em&gt;“JSON and JSON SMILE (binary json format) encoding/decoding”&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
I’m currently using &lt;code&gt;[cheshire "5.9.0"]&lt;/code&gt; successfully in production. My favourite thing about cheshire is that when parsing JSON it can automatically convert the keys to keywords in Clojure. I must admit I’ve abuse this feature in places where I probably shouldn’t have. Haha.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. http-kit
&lt;/h3&gt;

&lt;p&gt;http-kit is a &lt;em&gt;“minimalist, event-driven, high-performance Clojure HTTP server/client library”&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
I’m currently using &lt;code&gt;[http-kit "2.4.0-alpha3"]&lt;/code&gt; successfully in production. #cowboy&lt;br&gt;&lt;br&gt;
My favourite thing about http-kit is that the HTTP client is really straight forward. Checkout the &lt;a href="http://www.http-kit.org/client.html#options"&gt;docs&lt;/a&gt;, you’ll see what I mean.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. nippy
&lt;/h3&gt;

&lt;p&gt;nippy is a &lt;em&gt;“high-performance serialization library for Clojure”&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
I’m currently using &lt;code&gt;[com.taoensso/nippy "2.14.0"]&lt;/code&gt; successfully in production. My favourite thing about nippy (besides it being rediculously fast) is that after processing large datasets I can save the object straight from memory directly to disk. This allows my application to pick up instantaneously from where it left off after a reboot.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. at-at
&lt;/h3&gt;

&lt;p&gt;at-at is an &lt;em&gt;“ahead-of-time function scheduler”&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
I’m currently using &lt;code&gt;[overtone/at-at "1.2.0"]&lt;/code&gt; successfully in production. My favourite &lt;a href="///blog/2019/09/11/overtone-music-to-keep-my-dynos-awake.html"&gt;trick&lt;/a&gt; with at-at is to use it to schedule a ping every 5 minutes to keep my dynos awake. Obviously I use http-kit to do the ping.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. charmander
&lt;/h3&gt;

&lt;p&gt;charmander is a &lt;em&gt;“set of libraries to make working with firebase easier in clojure”&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
I’m currently using &lt;code&gt;[alekcz/charmander "0.6.0"]&lt;/code&gt; successfully in production.&lt;br&gt;&lt;br&gt;
My favourite thing about charmander is that it has been the project that has taught me the most about clojure. Writing it has been one heck of a journey.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post is part of the &lt;a href="https://alexanderoloo.com/blog/2019/12/01/advent-of-parens.html"&gt;"Advent of Parens"&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>libraries</category>
      <category>day4</category>
    </item>
    <item>
      <title>Living Clojure</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Tue, 03 Dec 2019 07:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/living-clojure-3pko</link>
      <guid>https://forem.com/alekcz/living-clojure-3pko</guid>
      <description>&lt;p&gt;There was a time where I was so fed up with lisps, Clojure, stack traces, and EOF errors. I was ready to go back to Node.js. And then I came a turning point. I stumbled across &lt;a href="https://www.functionalgeekery.com/episode-29-carin-meier/#t=4:43.525"&gt;episode 29&lt;/a&gt; of the Functional Geekery.&lt;/p&gt;

&lt;p&gt;The episode was an interview with &lt;a href="https://twitter.com/gigasquid"&gt;@gigasquid&lt;/a&gt;. It was entertaining and I learned a thing or two. And, and, she sounded like a normal human being. One who had had to work hard. I was energized. So after Functional Geekery, I looked for more podcasts with @gigasquid. There were a fair number of them. &lt;a href="http://shop.oreilly.com/product/0636920034292.do?sortby=publicationDate"&gt;Living Clojure&lt;/a&gt; had just come out and so everyone was keen to chat about it. It was great fun. I even ended up buying the book. Those podcasts became my companions as devoured the other episodes.&lt;/p&gt;

&lt;p&gt;Eventually, my travels led me to the &lt;a href="http://blog.cognitect.com/cognicast/088"&gt;Cognicast&lt;/a&gt;. It was amazing! There were close to 100 episodes (at the time). All relating to Clojure. On days when I was too tired to code, I listened to an episode of the Cognicast. Some days I would just listen to an episode for entertainment.&lt;/p&gt;

&lt;p&gt;Alternating between coding, reading and listening turned out to be a great way to keep forward momentum. It was like I was truly living Clojure. The switching contexts also helped me deal with the frustration of learning a new skill, in an calm, entertaining and educational way.&lt;/p&gt;

&lt;p&gt;Give it a try and lemme know how it goes for you. I’ll be on &lt;a href="https://twitter.com/alekcz"&gt;twitter&lt;/a&gt;. And remember when you get frustrated with Clojure, remember @gigasquid’s words: “Parens are like hugs for your code”. Do you really want to write code that’s deprived of hugs? Keep fighting the good fight. Keep living Clojure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zs6xvGCi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://alexanderoloo.com/images/blog/parens.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zs6xvGCi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://alexanderoloo.com/images/blog/parens.png" alt="Parens are like hugs for your code" title="Parens are like hugs for your code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Podcasts on Living Clojure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.functionalgeekery.com/episode-29-carin-meier/#t=4:43.525"&gt;Functional Geekery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.cognitect.com/cognicast/088"&gt;The Cognicast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hanselminutes.com/464/living-clojure-with-carin-meier"&gt;Hanselminutes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://changelog.com/podcast/171"&gt;Changelog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post is part of the &lt;a href="https://alexanderoloo.com/blog/2019/12/01/advent-of-parens.html"&gt;"Advent of Parens"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I know. I know. We were supposed to chat about dealing with dodgy internet while trying to learn Clojure. It’s been one heck of a day so we’ll have to chat about that next week.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>podcast</category>
      <category>adventofparens</category>
      <category>day3</category>
    </item>
    <item>
      <title>5 Tools for Getting Started with Clojure</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Mon, 02 Dec 2019 07:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/5-tools-for-getting-started-with-clojure-2j82</link>
      <guid>https://forem.com/alekcz/5-tools-for-getting-started-with-clojure-2j82</guid>
      <description>&lt;p&gt;Greetings friend. Today we’re going to talk Clojure tools. And no, you don’t have to use emacs. There are many tools and they’re all slightly different. Which tools are the best? Well, you see, like everything else in programming, it depends. It depends on many things. And therein lies the difficulty. Since our aim is to make it easier for people to enter the Clojure community we’re going to evaluate our decisions on beginner friendliness.&lt;/p&gt;

&lt;p&gt;A quick disclaimer: if your primary dev environment is Windows you’re in for a world of hurt. I’d strongly recommend getting your hands on a distribution of Unix. It’ll make it easier to get help online.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 5 tools
&lt;/h2&gt;

&lt;p&gt;To get started with Clojure you need 5 main tools.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An internet connection&lt;/li&gt;
&lt;li&gt;A terminal&lt;/li&gt;
&lt;li&gt;A Java SDK&lt;/li&gt;
&lt;li&gt;A build tool&lt;/li&gt;
&lt;li&gt;An editor&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. An internet connection
&lt;/h3&gt;

&lt;p&gt;Let’s be honest, without internet there is very little you can do in tech these days. You’ll need internet to download libraries required for your project and to get help when you’re stuck.&lt;/p&gt;

&lt;p&gt;The most of the time the libraries are small. The JavaSDK will be the primary data hog in the early days.&lt;/p&gt;

&lt;p&gt;If you’re internet situation is dodgy, let chat ~tomorrow~ next week about some possible work arounds.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. A terminal
&lt;/h3&gt;

&lt;p&gt;The default one will do just fine. &lt;strong&gt;#winning&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. A Java SDK
&lt;/h3&gt;

&lt;p&gt;Fortunately or unfortunately, depending on your point of view, Clojure requires Java. And yip there is more than one Java out there. From a beginner perspective, it’s almost irrelevant which one you pick.&lt;/p&gt;

&lt;p&gt;Going with &lt;a href="https://adoptopenjdk.net/"&gt;AdoptOpenJDK&lt;/a&gt; should create the least drama in your life. It’s free, open source, and supported by some &lt;a href="https://adoptopenjdk.net/sponsors.html"&gt;big names&lt;/a&gt; such AWS, Microsoft, Red Hat, and IBM to name a few.&lt;/p&gt;

&lt;p&gt;You can install AdoptOpenJDK on OSX like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ brew cask install adoptopenjdk

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And on Linux you can find the instructions for your distro &lt;a href="https://adoptopenjdk.net/installation.html"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If for some reason you ever need to pick a JVM, go with HotSpot. I have not idea which is better, but when in doubt and you have 0 expertise the beaten path is the way to go.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. A build tool
&lt;/h3&gt;

&lt;p&gt;It’s very possible to spend hours tinker with config and builds. In the beginning it’s very much shooting in the dark. &lt;a href="https://leiningen.org/"&gt;Leiningen&lt;/a&gt; is easy and straightforward. So for now let’s go with that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Leiningen is the easiest way to use Clojure. With a focus on project automation and declarative configuration, it gets out of your way and lets you focus on your code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are some others:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://boot-clj.com/"&gt;Boot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://clojure.org/guides/deps_and_cli"&gt;clj and deps.edn&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  An editor
&lt;/h3&gt;

&lt;p&gt;For some obscure reason, editors are a particularly charged topic. We’re definitely not getting into that here. Today is a day of peace and tranquility. Unfortunatley, even with lens of beginner friendliness the choice of editor does not become easier.&lt;/p&gt;

&lt;p&gt;The most important thing at this point is to pick an editor that feels comfortable. You’ll spend a lot of time in it so choose comfort.&lt;/p&gt;

&lt;p&gt;Here are the top 5 most used editors from &lt;a href="https://www.surveymonkey.com/results/SM-S9JVNXNQV/"&gt;The State of Clojure 2019&lt;/a&gt;. Pick one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Emacs&lt;/li&gt;
&lt;li&gt;IntelliJ&lt;/li&gt;
&lt;li&gt;Vim&lt;/li&gt;
&lt;li&gt;VS Code&lt;/li&gt;
&lt;li&gt;Atom&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These 5 all have some plugins that make the particularly friendly to Clojure developers, but that is a discussion for another day.&lt;/p&gt;

&lt;h2&gt;
  
  
  A final note
&lt;/h2&gt;

&lt;p&gt;All these recommendations are with the lens of beginner friendliness. As you work in Clojure some of these tools may no longer be fit for purpose and your preferences may change. So don’t get too attached. There are enough &lt;a href="https://twitter.com/bbatsov"&gt;emacs zealots&lt;/a&gt; out there.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post is part of the &lt;a href="https://alexanderoloo.com/blog/2019/12/01/advent-of-parens.html"&gt;"Advent of Parens"&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>tools</category>
      <category>adventofparens</category>
      <category>day2</category>
    </item>
    <item>
      <title>Advent of Parens</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Sun, 01 Dec 2019 07:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/advent-of-parens-5238</link>
      <guid>https://forem.com/alekcz/advent-of-parens-5238</guid>
      <description>&lt;p&gt;A few days ago &lt;a href="https://twitter.com/plexus"&gt;@plexus&lt;/a&gt; (civilian name: Arne Brasseur) shared a pretty cool idea on twitter: Write a blog post every day from the 1st of December to the 24th of December on somethings to do with Clojure. And so the &lt;a href="https://lambdaisland.com/blog/2019-11-25-advent-of-parens"&gt;“Advent of Parens”&lt;/a&gt; was born!&lt;/p&gt;

&lt;p&gt;The Clojure community is filled with elegant code and really smart people. There are, however, very few beginner-friendly tutorials and the documentation is sparse. At times it can be quite intimidating and discouraging. It was so for me. &lt;a href="http://shop.oreilly.com/product/0636920034292.do?sortby=publicationDate"&gt;Living Clojure&lt;/a&gt; by &lt;a href="https://twitter.com/gigasquid"&gt;@gigasquid&lt;/a&gt; was the turning point. It was a very accessible introduction to Clojure.&lt;/p&gt;

&lt;p&gt;I think accessible writing is critical for the Clojure community to flourish. That’s why I’m super excited about the “Advent of Parens”. I’m not sure I’ll manage all 24 days but I’ll try my absolute bestest. Catch you tomorrow.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>adventofparens</category>
      <category>day1</category>
    </item>
    <item>
      <title>Overtone: Music to keep my dynos awake</title>
      <dc:creator>Alexander Oloo</dc:creator>
      <pubDate>Wed, 11 Sep 2019 19:00:00 +0000</pubDate>
      <link>https://forem.com/alekcz/overtone-music-to-keep-my-dynos-awake-2jpl</link>
      <guid>https://forem.com/alekcz/overtone-music-to-keep-my-dynos-awake-2jpl</guid>
      <description>&lt;p&gt;In my earlier years, I worked with startups as well as the “idea guys” aka “Code this for me and I’ll give you equity in my idea”. So I quickly learnt to contain costs for each of the multiple ventures I was involved in.&lt;/p&gt;

&lt;p&gt;I had many misadventures with &lt;code&gt;nohup&lt;/code&gt;, &lt;code&gt;upstart&lt;/code&gt;, and &lt;code&gt;systemctl&lt;/code&gt;. My infrastructure of choice quickly became (and still is) Heroku. No frills. No nonsense. Just &lt;code&gt;git push&lt;/code&gt;. They have a free plan that could go up to 1000 hours (there are at most 744 hours in a month). All you have to do was verify your account AKA &lt;strong&gt;add your credit card&lt;/strong&gt; and you were right as rain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JbwZk-qu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://alexanderoloo.com/images/blog/heroku-dyno-pricing.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JbwZk-qu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://alexanderoloo.com/images/blog/heroku-dyno-pricing.png" alt="Heroku hobby pricing $0 per month" title="Heroku pricing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Verified accounts come with a monthly pool of 1000 Free dyno hours; unverified accounts receive 550.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The only slightly annoying thing was that the dyno would sleep after 30 minutes of inactivity. It was more than slightly annoying. Every now and then you’d hit the site or the API and you’d have to cold start the JVM. Not on my watch!&lt;/p&gt;

&lt;p&gt;I was pretty new to Clojure at the time and was pretty intimidated by all the complexity of scheduling libraries. So I figured that if I could find a music library (and there must be because Java) surely it would have a metronome or wave generator. And so I found &lt;code&gt;overtone&lt;/code&gt;: the Open Source toolkit for designing synthesizers and collaborating with music.&lt;/p&gt;

&lt;p&gt;After wading through the source code I found the timing part of the library: &lt;code&gt;overtone.music.time&lt;/code&gt;. My approach was pretty straight forward. I’d run the &lt;code&gt;interspaced&lt;/code&gt; function and ping the dyno every 5 minutes.&lt;/p&gt;

&lt;p&gt;And so I sang to keep my dynos awake.&lt;/p&gt;

&lt;p&gt;Here’s a REPL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="c1"&gt;; in your REPL with [overtone "0.10.3"] as a depdency&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;keepawake.core&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;'overtone.music.time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;keepawake.core&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ping!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"HTTP GET request"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; this would be the actual get request&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;keepawake.core&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;interspaced&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ping!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; this was originally 300000 milliseconds&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Eventually, it dawned on me to just use &lt;code&gt;overtone/at-at&lt;/code&gt; seeing as &lt;code&gt;overtone.music.time&lt;/code&gt; was using it anyway.So these days &lt;code&gt;at-at&lt;/code&gt; solves all my scheduling needs, while taking me down memory lane to a galaxy far, far away…&lt;/p&gt;

&lt;p&gt;&lt;em&gt;May your build always pass.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alex&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/overtone/overtone"&gt;https://github.com/overtone/overtone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Reading source code in depth&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>clojure</category>
      <category>overtone</category>
    </item>
  </channel>
</rss>
