<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<title>Zefira&#x27;s Digital Garden</title>
	<subtitle>Out beyond ideas of wrongdoing and rightdoing there is a garden. Let us meet there and talk about code.</subtitle>
	<link href="https://zefira.dev/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="https://zefira.dev"/>
	<generator uri="https://www.getzola.org/">Zola</generator>
	<updated>2015-08-01T00:00:00+00:00</updated>
	<id>https://zefira.dev/atom.xml</id>
	<entry xml:lang="en">
		<title>Using Datomic Pro with Boot</title>
		<published>2015-08-01T00:00:00+00:00</published>
		<updated>2015-08-01T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/using-datomic-pro-with-boot/" type="text/html"/>
		<id>https://zefira.dev/posts/using-datomic-pro-with-boot/</id>
		<content type="html">&lt;p&gt;I first heard about &lt;a href=&quot;http:&#x2F;&#x2F;www.datomic.com&#x2F;&quot;&gt;Datomic&lt;&#x2F;a&gt; shortly after it was initially
released. I think I almost immediately went and read all of the
documents that &lt;del&gt;&lt;a href=&quot;http:&#x2F;&#x2F;thinkrelevance.com&#x2F;&quot;&gt;Relevance&lt;&#x2F;a&gt;&lt;&#x2F;del&gt; &lt;a href=&quot;http:&#x2F;&#x2F;cognitect.com&#x2F;&quot;&gt;Cognitect&lt;&#x2F;a&gt; released about
it&#x27;s architecture. I was duly impressed, and really interested in
using it. In particular, the potential for
&lt;a href=&quot;http:&#x2F;&#x2F;www.datomic.com&#x2F;benefits.html&quot;&gt;time-travelling&lt;&#x2F;a&gt; was really interesting and
exciting to me.&lt;&#x2F;p&gt;
&lt;p&gt;At the time I had been tasked with writing some code to determine
usage metrics for our system. One of my boss&#x27;s hopes was that we could
generate usage data from some time ago as well to compare with our
current levels. Because we were using traditional relational databases
and hadn&#x27;t planned for this use case, that turned out to be
impossible. However, if we had been using Datomic, that back-dated
query would have been absolutely trivial.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;When I attempted to actually learn to use Datomic however, I was
overwhelmed by the intensity and relative scarcity of the
documentation. My general inexperience meant that I wasn&#x27;t prepared to
be an early adopter of this technology.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;My problem with the vast majority [of Datomic tutorials] is that
they seem to be written for people who don&#x27;t need a tutorial, and by
and large all have the stench of &amp;quot;read the code and you&#x27;ll
understand,&amp;quot; quickly coupled with &amp;quot;and if you don&#x27;t, you&#x27;re not smart
enough to use this technology anyway.&amp;quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I read this in a &lt;a href=&quot;http:&#x2F;&#x2F;ben.vandgrift.com&#x2F;2014&#x2F;04&#x2F;24&#x2F;a-clojure-datomic-web-app-tutorial.html&quot;&gt;tutorial blog about Datomic&lt;&#x2F;a&gt; that I
recently ran across. It neatly sums up how I felt about Datomic at
that time. So nothing much came of my first attempt to learn Datomic.&lt;&#x2F;p&gt;
&lt;p&gt;Recently though, my interest was piqued again by a talk given by one
of my current co-workers. At the same time, I&#x27;ve been inspired
recently to pick up again a project I started around the time I was
first interested in Datomic, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;rotateam&quot;&gt;Rotateam&lt;&#x2F;a&gt;. Given my recent
love affair&#x2F;obsession with Clojure, and in particular the
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;boot-clj&#x2F;boot&quot;&gt;Boot&lt;&#x2F;a&gt; project for creating Clojure &lt;a href=&quot;http:&#x2F;&#x2F;boot-clj.com&#x2F;&quot;&gt;build tooling&lt;&#x2F;a&gt;, I
obviously wanted to rebuild the project using a
Boot&#x2F;Clojure&#x2F;Clojurescript stack. And what better database technology
to use than Datomic!&lt;&#x2F;p&gt;
&lt;p&gt;I chose to tackle the part I was least familiar with first: Datomic. I
followed the links and instructions from the Datomic home page until I
found out about the new (to me at least) free license for
&lt;a href=&quot;http:&#x2F;&#x2F;www.datomic.com&#x2F;get-datomic.html&quot;&gt;Datomic Pro Starter Edition&lt;&#x2F;a&gt;. From there I just followed
the getting started instructions and the tutorial.&lt;&#x2F;p&gt;
&lt;p&gt;Since Datomic is very proprietary software, the jar&#x27;s for it aren&#x27;t
available from public repositories. Instead, when you register with My
Datomic you get a generated password that gives you access to their
private, password-protected Maven repository. Conveniently, when you
sign up for the Starter Edition you are presented with a page that
tells you how to setup Maven and Leiningen projects to pull from these
repositories. They show you an excellent setup too, that doesn&#x27;t
require the security-sin of committing secrets to a Git repository.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, since Boot is still a relative newcomer to the Clojure
ecosystem, there are no official Cognitect-supported instructions for
securely using the My Datomic Maven repository with Boot.&lt;&#x2F;p&gt;
&lt;p&gt;Sounds like the perfect opportunity for a blog post :D&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a id=&quot;top-down&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;top-down&quot;&gt;&lt;a href=&quot;#top-down&quot; aria-label=&quot;Anchor link for: top-down&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Top Down&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s start from what we want to be able to do. In an ideal world, I
would be able to simply include Datomic Pro as a dependency in my
&lt;code&gt;:dependencies&lt;&#x2F;code&gt; list. In a typical &lt;code&gt;build.boot&lt;&#x2F;code&gt; file that would look
like this:&lt;&#x2F;p&gt;
&lt;h5 id=&quot;build-boot&quot;&gt;&lt;a href=&quot;#build-boot&quot; aria-label=&quot;Anchor link for: build-boot&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
build.boot&lt;&#x2F;h5&gt;
&lt;pre data-lang=&quot;clj&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clj &quot;&gt;&lt;code class=&quot;language-clj&quot; data-lang=&quot;clj&quot;&gt;&lt;span&gt;(set-env!
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:dependencies &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;[[com.datomic&#x2F;datomic-pro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;0.9.5206&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]])
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we try this out it pretty clearly fails. On my machine Boot spat
out a huge amount of junk that boiled down to &amp;quot;Sorry chap, I couldn&#x27;t
find version &lt;code&gt;0.9.5206&lt;&#x2F;code&gt; of &lt;code&gt;com.datomic&#x2F;datomic-pro&lt;&#x2F;code&gt; for you.&amp;quot; Of
course, this is because we haven&#x27;t told boot how to look in the Maven
repository where it exists: &lt;code&gt;https:&#x2F;&#x2F;my.datomic.com&#x2F;repo&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s try the simplest thing that could possibly work. If we look at
the Boot
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;boot-clj&#x2F;boot&#x2F;wiki&#x2F;Boot-Environment#env-keys&quot;&gt;documentation on the keys in the Boot environment&lt;&#x2F;a&gt;, we can
see that there is a handy &lt;code&gt;:repositories&lt;&#x2F;code&gt; key that we should probably
be setting with the details of our My Datomic credentials. If we check
out the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cemerick&#x2F;pomegranate&#x2F;blob&#x2F;pomegranate-0.3.0&#x2F;src&#x2F;main&#x2F;clojure&#x2F;cemerick&#x2F;pomegranate&#x2F;aether.clj#L639-L650&quot;&gt;documentation in Pomegranate&lt;&#x2F;a&gt; for what the values of
the &lt;code&gt;:repositories&lt;&#x2F;code&gt; vector should look like, we can see that to
include authentication credentials, we need to specify it as a
map. Concretely our &lt;code&gt;build.boot&lt;&#x2F;code&gt; should look more like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a id=&quot;first-working&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h5 id=&quot;build-boot-1&quot;&gt;&lt;a href=&quot;#build-boot-1&quot; aria-label=&quot;Anchor link for: build-boot-1&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
build.boot&lt;&#x2F;h5&gt;
&lt;pre data-lang=&quot;clj&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clj &quot;&gt;&lt;code class=&quot;language-clj&quot; data-lang=&quot;clj&quot;&gt;&lt;span&gt;(set-env!
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:dependencies &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;[[com.datomic&#x2F;datomic-pro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;0.9.5206&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]]
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:repositories
&lt;&#x2F;span&gt;&lt;span&gt; #(conj % [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;my-datomic&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;https:&#x2F;&#x2F;my.datomic.com&#x2F;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                         &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:username &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;notmyemail@example.com&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                         &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:password &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;obviously-not-my-password&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}]))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The reason for the funny syntax of specifying a lambda function as the
repositories value is because we want to update the value
&lt;code&gt;:repositories&lt;&#x2F;code&gt; by adding (&lt;code&gt;conj&lt;&#x2F;code&gt;ing) the &lt;code&gt;my-datomic&lt;&#x2F;code&gt; repository. We
can&#x27;t just blindly override the repositories, because by default Boot
adds entries for pulling from &lt;a href=&quot;http:&#x2F;&#x2F;search.maven.org&#x2F;&quot;&gt;Maven Central&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;clojars.org&#x2F;&quot;&gt;Clojars&lt;&#x2F;a&gt; which we probably don&#x27;t want to blow away.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a id=&quot;side-note&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;side-note&quot;&gt;&lt;a href=&quot;#side-note&quot; aria-label=&quot;Anchor link for: side-note&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Side Note&lt;&#x2F;h3&gt;
&lt;p&gt;Rather than bothering to go and read the Pomegranate documentation, we
also could have inspected Boot&#x27;s default environment. Boot ships with a
handy task called &lt;code&gt;show&lt;&#x2F;code&gt; which is useful for this sort of inspection.
For Leiningen users, it&#x27;s sort of equivalent to &lt;code&gt;lein pprint&lt;&#x2F;code&gt;. In this
case, since we&#x27;re interested in what&#x27;s in the environment we want to
run &lt;code&gt;boot show -e&lt;&#x2F;code&gt; or &lt;code&gt;boot show --env&lt;&#x2F;code&gt;.  And of course, as with all
Boot tasks we could find out this information by running &lt;code&gt;boot show -h&lt;&#x2F;code&gt;. Okay, &lt;code&gt;&amp;lt;&#x2F;side note&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a id=&quot;back-to-it&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;back-to-it&quot;&gt;&lt;a href=&quot;#back-to-it&quot; aria-label=&quot;Anchor link for: back-to-it&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Back to It&lt;&#x2F;h2&gt;
&lt;p&gt;Obviously you&#x27;d need to put your real My Datomic credentials in
there. Just as obviously, this can&#x27;t be the final form our solution
takes. The &lt;code&gt;build.boot&lt;&#x2F;code&gt; file pretty much &lt;em&gt;needs&lt;&#x2F;em&gt; to be under source
control, and those secrets need to &lt;strong&gt;&lt;em&gt;not&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; be present in source
control.&lt;&#x2F;p&gt;
&lt;p&gt;So &lt;a href=&quot;https:&#x2F;&#x2F;zefira.dev&#x2F;posts&#x2F;using-datomic-pro-with-boot&#x2F;#first-working&quot;&gt;that&lt;&#x2F;a&gt; works. But to develop a more elegant and
secure solution, we&#x27;re probably going to need a better understanding
of just how Boot goes about loading dependencies. Now, we could go and
read the source. Or we could treat Boot as a black box and play with
it until we have a better understanding of how it works. I vote the
latter.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s start with the simplest thing that probably &lt;strong&gt;won&#x27;t&lt;&#x2F;strong&gt; work. What if
we move the &lt;code&gt;:repositories&lt;&#x2F;code&gt; update into a separate &lt;code&gt;set-env!&lt;&#x2F;code&gt; like this:&lt;&#x2F;p&gt;
&lt;h5 id=&quot;build-boot-2&quot;&gt;&lt;a href=&quot;#build-boot-2&quot; aria-label=&quot;Anchor link for: build-boot-2&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
build.boot&lt;&#x2F;h5&gt;
&lt;pre data-lang=&quot;clj&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clj &quot;&gt;&lt;code class=&quot;language-clj&quot; data-lang=&quot;clj&quot;&gt;&lt;span&gt;(set-env!
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:dependencies &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;[[com.datomic&#x2F;datomic-pro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;0.9.5206&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]])
&lt;&#x2F;span&gt;&lt;span&gt;(set-env!
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:repositories
&lt;&#x2F;span&gt;&lt;span&gt; #(conj % [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;my-datomic&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;https:&#x2F;&#x2F;my.datomic.com&#x2F;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                         &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:username &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;notmyemail@example.com&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                         &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:password &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;obviously-not-my-password&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}]))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This again fails spectacularly for the same reason of not being able
to resolve the Datomic dependency. But this test has told us something
important. It tells us that the dependency resolution happened &lt;em&gt;during
the first call to &lt;code&gt;set-env!&lt;&#x2F;code&gt;&lt;&#x2F;em&gt;. This is important, because it implies
that if we get the &lt;code&gt;my-datomic&lt;&#x2F;code&gt; repository configuration into the boot
environment before that call, then everything should work just
fine. Let&#x27;s try it out:&lt;&#x2F;p&gt;
&lt;h5 id=&quot;build-boot-3&quot;&gt;&lt;a href=&quot;#build-boot-3&quot; aria-label=&quot;Anchor link for: build-boot-3&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
build.boot&lt;&#x2F;h5&gt;
&lt;pre data-lang=&quot;clj&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clj &quot;&gt;&lt;code class=&quot;language-clj&quot; data-lang=&quot;clj&quot;&gt;&lt;span&gt;(set-env!
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:repositories
&lt;&#x2F;span&gt;&lt;span&gt; #(conj % [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;my-datomic&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;https:&#x2F;&#x2F;my.datomic.com&#x2F;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                         &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:username &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;notmyemail@example.com&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                         &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:password &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;obviously-not-my-password&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}]))
&lt;&#x2F;span&gt;&lt;span&gt;(set-env!
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:dependencies &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;[[com.datomic&#x2F;datomic-pro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;0.9.5206&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]])
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hey, presto! It works. Let&#x27;s think about why this works for a moment
and what the implications are. Obviously, at some point during the
&lt;code&gt;set-env!&lt;&#x2F;code&gt; function, some code gets called that notices that a new
dependency was added, and attempts to resolve it. As long as the
repository required to resolve that dependency is present in the list
of repositories at that moment, then everything works fine. This is an
excellent example of what the Boot authors are talking about when they
say that Boot builds are programs.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re like me then long familiarity with declarative build systems
has lulled you into thinking of build description files as
fundamentally not code. Even though a Leiningen project map is
entirely made of Clojure data structures, my experiences have taught
me that it isn&#x27;t really code. But a Boot build file is. It&#x27;s really just
executing Clojure code.&lt;&#x2F;p&gt;
&lt;p&gt;When I was first discovering how this worked for myself, I was working
on an actual project, and the &lt;code&gt;build.boot&lt;&#x2F;code&gt; was significantly more
complex. As such, I broke out the Datomic specific portions into the
snippets that I&#x27;ve included in this blog post. But because of my
build&#x27;s-as-specification indoctrination, I had fallen into a rhythm of
always having my &lt;code&gt;build.boot&lt;&#x2F;code&gt; files have a certain structure to them.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;my-prototypical-build-boot&quot;&gt;&lt;a href=&quot;#my-prototypical-build-boot&quot; aria-label=&quot;Anchor link for: my-prototypical-build-boot&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
My prototypical build.boot&lt;&#x2F;h5&gt;
&lt;pre data-lang=&quot;clj&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clj &quot;&gt;&lt;code class=&quot;language-clj&quot; data-lang=&quot;clj&quot;&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; Start with source paths and dependencies
&lt;&#x2F;span&gt;&lt;span&gt;(set-env!
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:source-paths &lt;&#x2F;span&gt;&lt;span&gt;#{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;src&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:dependencies &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;[[org.clojure&#x2F;clojure      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;1.6.0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;                 [midje                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;1.7.0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;          &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:scope &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;                 [zilti&#x2F;boot-midje         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;0.2.1-SNAPSHOT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:scope &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;                 [radicalzephyr&#x2F;bootlaces  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;0.1.15-SNAPSHOT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]])
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; Require bootlaces and other boot tasks
&lt;&#x2F;span&gt;&lt;span&gt;(require &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;[radicalzephyr.bootlaces &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:refer :all&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;[zilti.boot-midje        &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:refer &lt;&#x2F;span&gt;&lt;span&gt;[midje]])
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; Define the project version
&lt;&#x2F;span&gt;&lt;span&gt;(def +version+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;0.1.1-SNAPSHOT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; And use the bootlaces configuration
&lt;&#x2F;span&gt;&lt;span&gt;(bootlaces! +version+)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; Finally, configure any default task-options
&lt;&#x2F;span&gt;&lt;span&gt;(task-options!
&lt;&#x2F;span&gt;&lt;span&gt; pom  {&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:project     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;radicalzephyr&#x2F;rotateam
&lt;&#x2F;span&gt;&lt;span&gt;       &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:version     &lt;&#x2F;span&gt;&lt;span&gt;+version+
&lt;&#x2F;span&gt;&lt;span&gt;       &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:description &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;A web-app for scheduling team role rotations.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;       &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:url         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;radicalzephyr&#x2F;clj-rotateam&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;       &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:scm         &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;radicalzephyr&#x2F;clj-rotateam&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;       &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:license     &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;Eclipse Public License&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;http:&#x2F;&#x2F;www.eclipse.org&#x2F;legal&#x2F;epl-v10.html&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}})
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This structure is &lt;em&gt;very&lt;&#x2F;em&gt; reminiscent of a &lt;code&gt;project.clj&lt;&#x2F;code&gt; file. It&#x27;s
format is slightly different, but there&#x27;s really nothing that takes
advantage of the fact that this is actually a regular Clojure
program. This is true for a reason though, and again it&#x27;s mentioned in
Boot&#x27;s rationale. Simple projects don&#x27;t need the flexibility of having
their build be a real program. But here&#x27;s the thing, simple projects
tend to become complex projects over time.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a id=&quot;back-to-datomic&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;back-to-datomic&quot;&gt;&lt;a href=&quot;#back-to-datomic&quot; aria-label=&quot;Anchor link for: back-to-datomic&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Back to Datomic&lt;&#x2F;h2&gt;
&lt;p&gt;Okay, enough philosophizing. What does this build as program mean for
storing and accessing our My Datomic credentials securely? Well for
starters, it means we can do something really simple like following
the Heroku paradigm of putting secrets into environment
variables. Pulling them out is easy with a little bit of Java-interop.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;build-boot-4&quot;&gt;&lt;a href=&quot;#build-boot-4&quot; aria-label=&quot;Anchor link for: build-boot-4&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
build.boot&lt;&#x2F;h5&gt;
&lt;pre data-lang=&quot;clj&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clj &quot;&gt;&lt;code class=&quot;language-clj&quot; data-lang=&quot;clj&quot;&gt;&lt;span&gt;(set-env!
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:dependencies &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;[[com.datomic&#x2F;datomic-pro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;0.9.5206&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]]
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:repositories
&lt;&#x2F;span&gt;&lt;span&gt; #(conj % [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;my-datomic&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;https:&#x2F;&#x2F;my.datomic.com&#x2F;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                         &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:username &lt;&#x2F;span&gt;&lt;span&gt;(System&#x2F;getenv &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;DATOMIC_USERNAME&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;                         &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:password &lt;&#x2F;span&gt;&lt;span&gt;(System&#x2F;getenv &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;DATOMIC_PASSWORD&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)}]))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This again works perfectly. But why stop there? This solution only
works when you have your Datomic username and password set as
environment variables. Instead, we could fallback to prompting the
user for the credentials. Borrowing and adapting some code from
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;adzerk-oss&#x2F;bootlaces&quot;&gt;Adzerk&#x27;s bootlaces&lt;&#x2F;a&gt;, we can provide a reasonable
fallback experience.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;build-boot-5&quot;&gt;&lt;a href=&quot;#build-boot-5&quot; aria-label=&quot;Anchor link for: build-boot-5&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
build.boot&lt;&#x2F;h5&gt;
&lt;pre data-lang=&quot;clj&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clj &quot;&gt;&lt;code class=&quot;language-clj&quot; data-lang=&quot;clj&quot;&gt;&lt;span&gt;(let [[user pass] (mapv #(System&#x2F;getenv %)
&lt;&#x2F;span&gt;&lt;span&gt;                        [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;DATOMIC_USERNAME&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;DATOMIC_PASS&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;      datomic-creds (atom {})]
&lt;&#x2F;span&gt;&lt;span&gt;  (if (and user pass)
&lt;&#x2F;span&gt;&lt;span&gt;    (swap! datomic-creds assoc &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:username &lt;&#x2F;span&gt;&lt;span&gt;user &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:password &lt;&#x2F;span&gt;&lt;span&gt;pass)
&lt;&#x2F;span&gt;&lt;span&gt;    (do (println (str &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;DATOMIC_USERNAME and DATOMIC_PASS were not set;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt; please enter your Datomic credentials.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;        (print &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;Username: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;        (#(swap! datomic-creds assoc &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:username &lt;&#x2F;span&gt;&lt;span&gt;%) (read-line))
&lt;&#x2F;span&gt;&lt;span&gt;        (print &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;Password: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;        (#(swap! datomic-creds assoc &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:password &lt;&#x2F;span&gt;&lt;span&gt;%)
&lt;&#x2F;span&gt;&lt;span&gt;         (apply str (.readPassword (System&#x2F;console))))))
&lt;&#x2F;span&gt;&lt;span&gt;  (set-env! &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:repositories
&lt;&#x2F;span&gt;&lt;span&gt;            #(conj % [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;my-datomic&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                      (merge &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;datomic-creds
&lt;&#x2F;span&gt;&lt;span&gt;                             {&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;https:&#x2F;&#x2F;my.datomic.com&#x2F;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;})])))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This code may look a bit intimidating, but it&#x27;s mostly managing the
details of user friendly input and output. But again, why stop here?
This is &lt;em&gt;just Clojure code&lt;&#x2F;em&gt; here, so all of Clojure&#x27;s ability to
define and use abstractions is right there.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;build-boot-6&quot;&gt;&lt;a href=&quot;#build-boot-6&quot; aria-label=&quot;Anchor link for: build-boot-6&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
build.boot&lt;&#x2F;h5&gt;
&lt;pre data-lang=&quot;clj&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clj &quot;&gt;&lt;code class=&quot;language-clj&quot; data-lang=&quot;clj&quot;&gt;&lt;span&gt;(defn get-cleartext [prompt]
&lt;&#x2F;span&gt;&lt;span&gt;  (print prompt)
&lt;&#x2F;span&gt;&lt;span&gt;  (read-line))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(defn get-password [prompt]
&lt;&#x2F;span&gt;&lt;span&gt;  (print prompt)
&lt;&#x2F;span&gt;&lt;span&gt;  (apply str (.readPassword (System&#x2F;console))))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(let [user
&lt;&#x2F;span&gt;&lt;span&gt;      (or (System&#x2F;getenv &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;DATOMIC_USERNAME&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;          (get-cleartext &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;DATOMIC_USERNAME was not defined.&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;Username: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;      pass
&lt;&#x2F;span&gt;&lt;span&gt;      (or (System&#x2F;getenv &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;DATOMIC_PASSORD&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;          (get-password  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;DATOMIC_PASSWORD was not defined.&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;Password: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))]
&lt;&#x2F;span&gt;&lt;span&gt;  (set-env! &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:repositories
&lt;&#x2F;span&gt;&lt;span&gt;            #(conj % [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;my-datomic&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;https:&#x2F;&#x2F;my.datomic.com&#x2F;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                                    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:username &lt;&#x2F;span&gt;&lt;span&gt;user
&lt;&#x2F;span&gt;&lt;span&gt;                                    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:password &lt;&#x2F;span&gt;&lt;span&gt;pass}])))
&lt;&#x2F;span&gt;&lt;span&gt;(set-env!
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:dependencies &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;[[com.datomic&#x2F;datomic-pro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;0.9.5206&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]])
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There&#x27;s still some obvious duplication in there. Let&#x27;s see if we can
get rid of that too.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;build-boot-7&quot;&gt;&lt;a href=&quot;#build-boot-7&quot; aria-label=&quot;Anchor link for: build-boot-7&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
build.boot&lt;&#x2F;h5&gt;
&lt;pre data-lang=&quot;clj&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clj &quot;&gt;&lt;code class=&quot;language-clj&quot; data-lang=&quot;clj&quot;&gt;&lt;span&gt;(defn get-cleartext [prompt]
&lt;&#x2F;span&gt;&lt;span&gt;  (print prompt)
&lt;&#x2F;span&gt;&lt;span&gt;  (read-line))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(defn get-password [prompt]
&lt;&#x2F;span&gt;&lt;span&gt;  (print prompt)
&lt;&#x2F;span&gt;&lt;span&gt;  (apply str (.readPassword (System&#x2F;console))))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(require &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;[clojure.string &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:as &lt;&#x2F;span&gt;&lt;span&gt;str])
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(defn get-env-or-prompt [prefix prompt-fmt word get-fn]
&lt;&#x2F;span&gt;&lt;span&gt;  (let [env-name (str prefix word)]
&lt;&#x2F;span&gt;&lt;span&gt;    (or (System&#x2F;getenv env-name)
&lt;&#x2F;span&gt;&lt;span&gt;        (get-fn (format prompt-fmt env-name (str&#x2F;capitalize word))))))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(let [[user pass] (mapv #(get-env-or-prompt &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;DATOMIC_&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                                            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;%s was not defined.&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                                            %1 %2)
&lt;&#x2F;span&gt;&lt;span&gt;                        [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;USERNAME&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;PASSWORD&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;                        [get-cleartext get-password])]
&lt;&#x2F;span&gt;&lt;span&gt;  (set-env! &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:repositories
&lt;&#x2F;span&gt;&lt;span&gt;            #(conj % [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;my-datomic&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;https:&#x2F;&#x2F;my.datomic.com&#x2F;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                                    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:username &lt;&#x2F;span&gt;&lt;span&gt;user
&lt;&#x2F;span&gt;&lt;span&gt;                                    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:password &lt;&#x2F;span&gt;&lt;span&gt;pass}])))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(set-env!
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:dependencies &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;[[com.datomic&#x2F;datomic-pro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;0.9.5206&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]])
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The code is longer now, but it&#x27;s been decomposed and de-duplicated
significantly. It also gained the ability to prompt for values only if
the corresponding environment variable isn&#x27;t set. We could keep going
with this, and define that &lt;code&gt;let&lt;&#x2F;code&gt; block as a function. We could move
all this code into a Clojure source file in the &lt;code&gt;src&lt;&#x2F;code&gt; folder of the
current project, and then &lt;code&gt;require&lt;&#x2F;code&gt; it in. Or we could put it into a
separate library like &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;radicalzephyr&#x2F;rotateam&quot;&gt;my bootlaces&lt;&#x2F;a&gt; and add that as a
dependency. Once we extract this functionality into a library we could
add tests for it, and then continue to expand it&#x27;s functionality. We
could add another method for retrieving the credentials. Perhaps
storing them in an encrypted edn file, which we read in if it exists.&lt;&#x2F;p&gt;
&lt;p&gt;All of these various permutations are possible, and more. And we
always have the full power of Clojure at our disposal. Notice what we
didn&#x27;t have to do at any point along this process. We didn&#x27;t have to
write a plugin for our build tool, or try to get a patch merged into
the source code and wait for it&#x27;s release. It&#x27;s all just been regular
Clojure code, following a very natural and easy code growth
path. Start out with an inline-definition and usage, then slowly
abstract and tease apart into a separate package.&lt;&#x2F;p&gt;
&lt;p&gt;This is the philosophy of Lisp writ large in the paradigm of building
programs. There is no difference between what is built into Boot, and
what we define personally. There is nothing done in the Boot built-in
tasks that could not have been done by a Boot user. Based on a few
carefully chosen &amp;quot;primitives&amp;quot; an elegant and powerful structure can be
built. This is what happens when your code is just data, or your build
is just a program.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>The Importance of Focusing Small with TDD</title>
		<published>2015-07-23T00:00:00+00:00</published>
		<updated>2015-07-23T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/the-importance-of-focusing-small-with-tdd/" type="text/html"/>
		<id>https://zefira.dev/posts/the-importance-of-focusing-small-with-tdd/</id>
		<content type="html">&lt;p&gt;Since I&#x27;ve been an apprentice at 8th Light, I&#x27;ve been focusing on
really trying to &lt;em&gt;get&lt;&#x2F;em&gt; TDD as a practice and a discipline. As part of
that I&#x27;ve done a lot of reading and reflecting on past reading&#x27;s about
TDD. One thing that jumped out at me about the way that Martin Fowler
and Kent Beck all talk about TDD: they all tend to say mildly
self-deprecating things like: &amp;quot;I&#x27;m just not smart enough to hold all
that complexity in my head.  TDD helps me get away with not seeing the
big picture.&amp;quot; But I think this statement is fundamentally misleading.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;I was always a little confused when I read statements like that,
because to me the clarity of their writing and thoughts indicate to me
that they are in fact pretty smart. Another way they say it is that
&amp;quot;you don&#x27;t have to be super smart to do TDD.&amp;quot; I think this is a
genuine statement, but it&#x27;s about marketing TDD than about explaining
how to do it.&lt;&#x2F;p&gt;
&lt;p&gt;When I was writing Tic-Tac-Toe in Ruby during the first month of my
apprenticeship though, I was trying to rigorously test-drive all of
the development in a very intentional way for the first time in my
coding career. As I got into the swing of things, I started noticing
that I was focusing on smaller portions of the code.&lt;&#x2F;p&gt;
&lt;p&gt;Normally when I&#x27;m programming, I have something close to
&lt;a href=&quot;http:&#x2F;&#x2F;heeris.id.au&#x2F;2013&#x2F;this-is-why-you-shouldnt-interrupt-a-programmer&#x2F;&quot;&gt;this experience&lt;&#x2F;a&gt;. I try and build up an understanding
and mental structure of as much of the program as I can hold in my
head at once. I do this largely because if I have the structure of the
whole program in my head then I know that when I make changes, they&#x27;re
going to be good ones, and remain consistent with the rest of the
program.&lt;&#x2F;p&gt;
&lt;p&gt;One of the benefits of TDD is that you end up with a
comprehensive test suite for your program as you build it. So instead
of having to build a huge mental model of the software as you are
programming, you can simply make a change and then run the test
suite. This will tell you, with far greater accuracy, whether the
change is consistent with the state of the actual program. There&#x27;s no
layer of indirection through a potentially inconsistent mental model.&lt;&#x2F;p&gt;
&lt;p&gt;So, having tests allows you not to have a large mental model of the
program you&#x27;re building. Another (desirable!) consequence of rigorous
test-driving is a well-factored design. If the components in your
system have small, well-defined responsibilities and interact with
other components in reasonable and well-defined ways the system is
simpler.  When the system is simpler you can get away with having only
a local view of the code when making changes, so you don&#x27;t have to be
&amp;quot;as smart.&amp;quot;&lt;&#x2F;p&gt;
&lt;p&gt;But here&#x27;s the thing, these are reasons why you can still program
without a comprehensive understanding of the codebase when practicing
TDD. But the revelation that I had, what caused me to say that Martin
Fowler and company are being misleading, is that I think TDD is actually
&lt;em&gt;easier&lt;&#x2F;em&gt; to do when you let go of trying to build a comprehensive mental
model of the code. This is more true the more of that context you can
hold in your head.&lt;&#x2F;p&gt;
&lt;p&gt;I had a friend in college who was arguably a genius. Assignments that
the rest of our class would take a week to do, he would churn out in a
12-hour Mountain Dew-fueled frenzy of coding. He would intentionally
seek to make assignments more challenging - for example doing a simple
assembly language project, he developed an Object Oriented style of
assembly programming because it would have been boring to him
otherwise.&lt;&#x2F;p&gt;
&lt;p&gt;I ended up working with him on a number of projects though, and I
discovered something. I thought that I had a tendency to overengineer
solutions, but my proclivities in that regard were nothing compared to
my friend&#x27;s.&lt;&#x2F;p&gt;
&lt;p&gt;One summer we decided to create an AI to play the video game StarCraft
and enter it in a contest at the end of the summer.  When we were
planning the architecture of the AI , he immediately started
describing this incredibly elaborate structure, with pluggable modules
that would allow swapping out of different components of the AI, and a
tiered architecture of decision making that would separate the low
level movements of units from the tactical and strategic
decision-making required to win the game.&lt;&#x2F;p&gt;
&lt;p&gt;This structure was impressive and compelling, and we spent weeks
talking about it and sketching diagrams and class hierarchies on the
whiteboard. It would have been helpful to have such a modular
architecture if we had a large team of people working on it, and the
initial meeting seemed to indicate there was a lot of interest. But
after a few weeks, interest in the project waned and most people
drifted away and that grand architecture was never needed and never
built.&lt;&#x2F;p&gt;
&lt;p&gt;From what I&#x27;ve seen, most of the best programmers that I know have
this tendency to over-engineer solutions. From what I&#x27;ve read, this is
not an isolated phenomenon in my social circle.&lt;&#x2F;p&gt;
&lt;p&gt;This type of pure thought design work is actually very similar to
building a mental model of how a piece of software works. It&#x27;s really
just a change in tense: over-engineering is just building a mental
model of how a piece of software &lt;em&gt;will&lt;&#x2F;em&gt; work, in the future. I&#x27;m sure
there is some fascinating psychology behind why this is such a common
tendency. I think what focusing on TDD in this intensive way taught me
is that the smaller your mental model of a piece of software is, the
more restricted your focus is, and the easier it is to refrain from
attempting to over-engineer it.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>TDD and the Art of Picking Tests</title>
		<published>2015-07-19T00:00:00+00:00</published>
		<updated>2015-07-19T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/tdd-and-the-art-of-picking-tests/" type="text/html"/>
		<id>https://zefira.dev/posts/tdd-and-the-art-of-picking-tests/</id>
		<content type="html">&lt;blockquote&gt;
&lt;p&gt;The first [problem] is stuckness, a mental stuckness that
accompanies the physical stuckness of whatever it is you&#x27;re working
on. A screw sticks, for example, on a side cover assembly. You check
the manual to see if there might be any special cause for this screw
to come off so hard, but all it says is &amp;quot;Remove side cover plate&amp;quot; in
that wonderful terse technical style that never tells you what you
want to know. There&#x27;s no earlier procedure left undone that might
cause the cover screws to stick.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re experienced you&#x27;d probably apply a penetrating liquid and
an impact driver at this point. But suppose you&#x27;re inexperienced and
you attach a self-locking plier wrench to the shank of your
screwdriver and really twist it hard, a procedure you&#x27;ve had success
with in the past, but which this time succeeds only in tearing the
slot of the screw.&lt;&#x2F;p&gt;
&lt;p&gt;Your mind was already thinking ahead to what you would do when the
cover plate was off, and so it takes a little time to realize that
this irritating minor annoyance of a torn screw slot isn&#x27;t just
irritating and minor. You&#x27;re stuck. Stopped. Terminated. It&#x27;s
absolutely stopped you from fixing the motorcycle.&lt;&#x2F;p&gt;
&lt;p&gt;-Robert Pirsig, &lt;em&gt;Zen and the Art of Motorcycle Maintenance&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;There is so much interesting material here it could take a while to
dig into all of it.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;h2 id=&quot;mental-stuckness&quot;&gt;&lt;a href=&quot;#mental-stuckness&quot; aria-label=&quot;Anchor link for: mental-stuckness&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Mental Stuckness&lt;&#x2F;h2&gt;
&lt;p&gt;Despite it&#x27;s total lack of physical tangibility software can get stuck
too, and as software developers when our software gets stuck, so do
we. The canonical example of stuck software is when we need to add a
new feature to our application, but it can&#x27;t be done without breaking
everything else. Usually we arrive in this situation because we don&#x27;t
have tests, and so we can&#x27;t refactor our code. We can only make
changes and then hope that everything still works.&lt;&#x2F;p&gt;
&lt;p&gt;There is another kind of stuckness though that is less specific to
software. The stuckness of a blank page. This is what Pirsig is
talking about in the above quote. Even when you&#x27;re rigorously
practicing TDD, this kind of stuckness can still affect you. It&#x27;s most
obvious when starting a new project from scratch. Then it really is
&amp;quot;blank page.&amp;quot; But I&#x27;ve noticed a similar feeling when I&#x27;m adding a new
&lt;em&gt;type&lt;&#x2F;em&gt; of functionality to an application.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cuttings&quot;&gt;&lt;a href=&quot;#cuttings&quot; aria-label=&quot;Anchor link for: cuttings&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Cuttings&lt;&#x2F;h3&gt;
&lt;p&gt;Pirsig spends the remainder of the chapter examining in detail what
stuckness means, and how to deal with it. Many of the&lt;&#x2F;p&gt;
&lt;p&gt;He describes it as the point at which what you think you know about
something has boxed you into a place where you can&#x27;t conceive of a way
to move forward.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Secure Password Storage</title>
		<published>2015-07-13T00:00:00+00:00</published>
		<updated>2015-07-13T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/secure-password-storage/" type="text/html"/>
		<id>https://zefira.dev/posts/secure-password-storage/</id>
		<content type="html">&lt;p&gt;At a high-level, when storing secrets like passwords, the standard
best practice is to never store the plain-text version of the password
in the system.  Instead, you store some information that is uniquely
and repeatably derived from the password in an irreversible fashion.
This is often called a &amp;quot;digest.&amp;quot;&lt;&#x2F;p&gt;
&lt;p&gt;This preserves the ability to check whether someone has entered the
correct password for an account in order to authenticate them (you
simply recalculate the derived value and check those for equality),
but it prevents an attacker who somehow obtains the password digest
from immediately having access to the plain-text version of a user&#x27;s
password. That&#x27;s the process at a very high-level.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;Now there are a number of different types of attacks that can be
executed against a web application and a legitimate user to attempt to
intercept the plain text version of a single user&#x27;s password.  The
defenses for these are well known, and all of the countermeasures that
are part of the source code of the app are being used.  There are some
further countermeasures (such as usage of https) that are a concern
of how the app is deployed, but we will certainly be implementing
those when we get to the point of production deployment.&lt;&#x2F;p&gt;
&lt;p&gt;This leaves the main attack vector for obtaining user passwords as
somehow obtaining access to the password digests that we store in our
database.  In our meeting on Thursday, Paul outlined some of the
deployment choices we can make to help prevent this from ever
occurring, but for illustrative purposes let&#x27;s assume that an attacker
has compromised our database in some manner and now has access to our
user password digests offline.&lt;&#x2F;p&gt;
&lt;p&gt;It is at this point that a detail I have glossed over becomes very
important: the method that we use to generate the password
digests. The industry standard is to use a key derivation function
(KDF). There are three current industry standard KDF&#x27;s: PBKDF2,
bcrypt, and scrypt.&lt;&#x2F;p&gt;
&lt;p&gt;All three of these KDF&#x27;s produce values that cannot be used to derive
the original key (i.e. the plain-text of the user password).  This
leaves two avenues of attack: a brute-force search for the original
password plain-text (a &amp;quot;preimage attack&amp;quot;), or a brute-force search for
another password plain-text that produces the same digest (a &amp;quot;collision
attack&amp;quot;).&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s important to realize that defending against a brute-force
password search is not a question of making it &amp;quot;impossible.&amp;quot;  It&#x27;s
really a question of how expensive it would be, and how long it would
take. The goal in this case is to make it so that the attacker can&#x27;t
try enough passwords in a &amp;quot;reasonable amount of time&amp;quot; that they will
get a sufficient return on the hardware they need to throw at the
problem, without making password authentication take so long that it
makes users upset.&lt;&#x2F;p&gt;
&lt;p&gt;At a high-level, all three of the industry standard KDF&#x27;s are tunable
as to how much time they take, so they effectively have equivalent
resistance to a brute-force attack.  However, PBKDF2 is a relatively
simple algorithm that can be very efficiently computed in specialized
hardware, or on commercial graphics cards.  This makes it
substantially weaker than the other two because graphics cards and
specialized hardware can increase the number of passwords that an
attacker can test per unit of time.&lt;&#x2F;p&gt;
&lt;p&gt;To quote an piece of writing I found about bcrypt:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Bcrypt has the best kind of repute that can be achieved for a
cryptographic algorithm: it has been around for quite some time,
used quite widely, &amp;quot;attracted attention&amp;quot;, and yet remains unbroken
to date.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Recently, advances in hardware have made bcrypt somewhat vulnerable in
a similar manner to PBKDF2.  Scrypt was designed to be tunable in both
speed and memory usage.  This tunable memory usage makes scrypt far
less susceptible to these specialized hardware attacks.&lt;&#x2F;p&gt;
&lt;p&gt;In general though these types of hardware attacks come at significant
cost, so for many applications tuned usage of PBKDF2 or bcrypt is more
than adequate.  Using scrypt also carries another form of risk. Since
it is a much newer algorithm it hasn&#x27;t had time to be subjected to the
same analysis and attack attempts as PBKDF2 and bcrypt.  This means
that it is possible for a security vulnerability to be discovered in
scrypt at some point in the future that makes it significantly less
secure than the other two.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Domain Driven Writing</title>
		<published>2015-07-03T00:00:00+00:00</published>
		<updated>2015-07-03T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/domain-driven-writing/" type="text/html"/>
		<id>https://zefira.dev/posts/domain-driven-writing/</id>
		<content type="html">&lt;p&gt;I&#x27;ve been reading &lt;em&gt;Domain Driven Design&lt;&#x2F;em&gt; by Eric Evans for the past
month or so, and thinking about the ideas and concepts in it has been
consuming a lot of my mental space and time. One thing in particular
that I&#x27;ve found to be really interesting is his concept of developing
a &lt;strong&gt;Ubiquitous Language&lt;&#x2F;strong&gt; for the project.&lt;&#x2F;p&gt;
&lt;p&gt;At a very high level, the idea of having a Ubiquitous Language for a
project just means that there is specific vocabulary and jargon that
is used to describe certain key concepts about the domain of the
project and the particular implementation that the team is
developing. Or to put it even more simply, that when someone on the
team uses a word or a phrase, everyone else knows what they are
talking about.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;This is actually something that people do constantly. You build up a
common language with the people you are closest to: your family,
friends, teammates at work. I know that my group of close friends has
a very particular way of speaking with one another, that probably
sounds somewhat odd to &amp;quot;outsiders.&amp;quot;&lt;&#x2F;p&gt;
&lt;p&gt;Sometimes it happens organically over a long period of time, and
sometimes we do it intentionally. My favorite example of this second
category are the talks that Rich Hickey gives. Some of them at least
have followed a particular format. He starts with the definition of a
word, possibly two. He defines them precisely, and he defines the
context that he is talking within. He then builds on this definition
to talk about some fundamental idea in programming, or some insight
that this rigorous definition gave him.&lt;&#x2F;p&gt;
&lt;p&gt;The key part though, is that a good portion of his talk is given to
building up a sort of basic common language so that he is confident
that when he uses a word, we understand as well as we possibly can
what he intended by saying it.&lt;&#x2F;p&gt;
&lt;p&gt;A good friend of mine often has a very hard time with this. I have had
many conversations with him about interesting and deep topics that
have turned into arguments, largely about what a particular word
means. The problem is often that he has a deeper context and specific
meaning that he intends when he says something. But because I haven&#x27;t
studied the same things or shared the same experiences, I don&#x27;t
realize he means something different than usual.&lt;&#x2F;p&gt;
&lt;p&gt;I wish I had a concrete example that I could talk about, because this
sounds very wish-washy.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-slight-digression&quot;&gt;&lt;a href=&quot;#a-slight-digression&quot; aria-label=&quot;Anchor link for: a-slight-digression&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
A Slight Digression&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;m strangely reminded of the final program from Mark Pilgrim&#x27;s
excellent - though sorely out-dated - &lt;em&gt;Dive Into Greasemonkey&lt;&#x2F;em&gt;. He
spends the first several tens of lines of code writing some facilities
that will make programming Javascript more reminiscent of programming
in Python because he&#x27;s so familiar with Python.&lt;&#x2F;p&gt;
&lt;p&gt;One thing that Eric Evans returns to throughout &lt;em&gt;DDD&lt;&#x2F;em&gt; is leaning on
the &lt;em&gt;Ubiquitous Language&lt;&#x2F;em&gt; of the project to suss out design issues
early. He emphasizes that we should try and engage all of our ways of
communicating and understanding the ideas of the project: with
language, with diagrams, and with code.&lt;&#x2F;p&gt;
&lt;p&gt;Uncle Bob has written at length about how (good) tests are really
specifications for how a program works. They should clearly
communicate the intent of the system.&lt;&#x2F;p&gt;
&lt;p&gt;Gerald Sussman and Hal Abelson write in the preface to their classic
&lt;em&gt;Structure and Interpretation of Computer Programs&lt;&#x2F;em&gt; that they believe
that programming is not just an activity concerned with causing
computers to enact computations. It is much more importantly &amp;quot;a novel
formal medium for expressing ideas about process.&amp;quot;&lt;&#x2F;p&gt;
&lt;p&gt;These two ideas, tests as specifications, and computer languages as
formal language describing processes have started to seem intimately
connected to me.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;automation-and-communication&quot;&gt;&lt;a href=&quot;#automation-and-communication&quot; aria-label=&quot;Anchor link for: automation-and-communication&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Automation and Communication&lt;&#x2F;h3&gt;
&lt;p&gt;Several years ago I was working on a project to build a video game AI
with several other students at my university. Another student and I
were pioneering the project, and in particular I took on the task of
figuring out how to get the development environment working on the
Computer Science lab machines.&lt;&#x2F;p&gt;
&lt;p&gt;This setup was non-trivial. It involved setting environment variables,
setting compatibility flags on the game executable, and installing
plugins into the game&#x27;s binary directory. On top of that, but because
of the way the lab machines were setup, there was additional setup
that needed to be done at the start of &lt;em&gt;every development session&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Once I had gotten everything working through a long process of trial
and error, I then set about attempting to duplicate my success from a
clean profile. As I figured out the minimal set of setup steps, I
wrote them down. I then proceeded to test the quality of these
instructions by handing them off to another student to replicate with
me watching over his shoulder.&lt;&#x2F;p&gt;
&lt;p&gt;You will of course be shocked to learn that he had almost no success
in following the steps I had written down. This is because I had
written them in enough detail for me to understand and remember
what needed to be done, but there was still a huge amount of context
for those instructions that resided only in my own head. Context that
I head gained by the laborious trial, error and troubleshooting
process of setting the environment up initially.&lt;&#x2F;p&gt;
&lt;p&gt;I iterated on the instructions several more times, each time finding
some new guinea pig to test them on. Until eventually, I came to the
conclusion that I would actually need pictures of the GUI dialogs and
full nearly click-by-click instructions in order to get a set of
instructions that other students could follow without making mistakes.&lt;&#x2F;p&gt;
&lt;p&gt;At that moment, I realized that I would be far less work, both
up-front and continuing to simply figure out how to write code to
automate the development environment setup.&lt;&#x2F;p&gt;
&lt;p&gt;This seems like a no-brainer. Write two scripts one time, spend a few
hours figuring out the nuances of scripting Windows and then tell
people &amp;quot;Download those two scripts. Run this one once, then run that
one every time you want to work on the project.&amp;quot; Done.&lt;&#x2F;p&gt;
&lt;p&gt;The problem for me is the same problem that a math tutor has with
simply telling the student the formula they need to use to calculate
the answer. There is a &lt;em&gt;lot&lt;&#x2F;em&gt; of important context that is missing.&lt;&#x2F;p&gt;
&lt;p&gt;My setup script was incredibly effective. Not only did it flawlessly
setup up the dev environment, but it was at least an order of
magnitude faster than for a human to accomplish the same tasks.&lt;&#x2F;p&gt;
&lt;p&gt;That small script I wrote, expressed the idea of how to setup that
development environment incredibly precisely. But there was now
something missing. There was no context for that process to fit in
to. The why of it was lost, and all that was left was for people to
run it.&lt;&#x2F;p&gt;
&lt;p&gt;Even reading the contents of the script, it was possible to determine
what it did, but the &lt;em&gt;why&lt;&#x2F;em&gt; was completely missing.&lt;&#x2F;p&gt;
&lt;p&gt;I think testing, at it&#x27;s very best, can start to supplement this
deficiency in code. It can help to answer the question &amp;quot;Yes, it
works. But why does it do it &lt;em&gt;that&lt;&#x2F;em&gt; way?&amp;quot;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;p-s&quot;&gt;&lt;a href=&quot;#p-s&quot; aria-label=&quot;Anchor link for: p-s&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
p.s.&lt;&#x2F;h4&gt;
&lt;p&gt;Some interesting papers that are somewhat related to this post:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.recurse.com&#x2F;blog&#x2F;58-paper-of-the-week-notation-as-a-tool-of-thought&quot;&gt;Notation as a Tool of Thought&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.recurse.com&#x2F;blog&#x2F;41-introducing-paper-of-the-week&quot;&gt;Growing A Language&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>The Many Faces of the Repository Pattern</title>
		<published>2015-06-29T00:00:00+00:00</published>
		<updated>2015-06-29T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/the-many-faces-of-the-repository-pattern/" type="text/html"/>
		<id>https://zefira.dev/posts/the-many-faces-of-the-repository-pattern/</id>
		<content type="html">&lt;p&gt;Last week I spent quite a lot of time working closely with my a fellow
apprentice on refactoring a Rails application away from direct usage
of ActiveRecord for data persistence, and towards some incarnation of
the Repository Pattern. Now that we&#x27;ve finished, I thought some
reflection on the different possible implementations that we
considered, and what we ended up implementing might be in order.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;h2 id=&quot;what-is-a-repository&quot;&gt;&lt;a href=&quot;#what-is-a-repository&quot; aria-label=&quot;Anchor link for: what-is-a-repository&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
What is a &amp;quot;Repository&amp;quot;?&lt;&#x2F;h2&gt;
&lt;p&gt;First of all, let&#x27;s talk briefly about the Repository Pattern
itself. My first exposure to the idea was through the discussion of it
in &amp;quot;Domain Driven Design&amp;quot; by Eric Evans. Martin Fowler has
&lt;a href=&quot;http:&#x2F;&#x2F;martinfowler.com&#x2F;eaaCatalog&#x2F;repository.html&quot;&gt;a page on Repositories&lt;&#x2F;a&gt; where he summarizes the pattern
with this description:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mediates between the domain and data mapping layers using a
collection-like interface for accessing domain objects.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This is a good high-level summary of what Eric Evans describes as
well. Broadly speaking, the idea is that you use the Repository
Pattern to thoroughly isolate your domain layer from whatever
strategies are used to persist the domain data. Evans offers this
description of the problem that Repositories help to solve:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;A subset of persistent objects must be globally accessible through a
search based on object attributes. ... Providing access to other
objects muddies important distinctions. Free database queries can
actually breach the encapsulation of domain objects and
AGGREGATES. Exposure of technical infrastructure and database access
mechanisms complicates the client and obscures the MODEL-DRIVEN
DESIGN.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;He further explains that:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;A repository lifts a huge burden from the client, which can now talk
to a simple, intention-revealing interface, and ask for what it
needs in terms of the model. To support all this requires a lot of
complex technical infrastructure, but the interface is simple and
conceptually connected to the domain model.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Finally, he lists the advantages that using Repositories confers:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;They present clients with a simple model for obtaining persistent
objects and managing their life cycle.&lt;&#x2F;li&gt;
&lt;li&gt;They decouple application and domain design from persistence
technology, multiple database strategies, or even multiple data
sources.&lt;&#x2F;li&gt;
&lt;li&gt;They communicate design decisions about object access.&lt;&#x2F;li&gt;
&lt;li&gt;They allow easy substitution of a dummy implementation, for use in
testing (typically using an in-memory collection).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For someone seeking to implement the Repository Pattern in their own
project, this list serves as an excellent barometer of the quality of
their implementation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;my-repository&quot;&gt;&lt;a href=&quot;#my-repository&quot; aria-label=&quot;Anchor link for: my-repository&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
My Repository&lt;&#x2F;h2&gt;
&lt;p&gt;A few weeks ago I started working on a new client project. It was a
greenfield application, and we started building it in Ruby on Rails,
using the basic Rails application structure, and all of the built-in
Rails Magic ™. This meant a standard MVC architecture,
ActiveRecord models, the whole nine yards.&lt;&#x2F;p&gt;
&lt;p&gt;We embraced the &amp;quot;Rails Way&amp;quot; largely to give the project a
jump-start. We were pretty confident that eventually we&#x27;d start
feeling the pain of using Rails and want to head towards some sort of
hybrid Rails architecture.&lt;&#x2F;p&gt;
&lt;p&gt;A few weeks ago, we got to that point and started looking at
implementing a repository for the new domain object we were about to
introduce. Unfortunately, I didn&#x27;t return to the discussion from the
DDD book referenced earlier, and we basically started to feel our way
into implementing the Repository pattern based on my teammates prior
experience, what we generally knew about the pattern and some
interesting examples we found on blog posts regarding using the
Repository pattern with Rails&#x27; ActiveRecord technology.&lt;&#x2F;p&gt;
&lt;p&gt;We ended up with something that looked basically like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;module &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8000;&quot;&gt;Notes
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Repository
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;initialize&lt;&#x2F;span&gt;&lt;span&gt;(dao &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6ae;&quot;&gt;Note&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;@dao &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; dao
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(attributes)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Notes&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Note&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(attributes)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;find_by_id&lt;&#x2F;span&gt;&lt;span&gt;(id)
&lt;&#x2F;span&gt;&lt;span&gt;      record &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;@dao&lt;&#x2F;span&gt;&lt;span&gt;.find_by_id(id)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Notes&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Note&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(record.attributes)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;save&lt;&#x2F;span&gt;&lt;span&gt;(note)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; note.valid?
&lt;&#x2F;span&gt;&lt;span&gt;        record &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;@dao&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(note.attributes).save
&lt;&#x2F;span&gt;&lt;span&gt;        note.id &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; record.id
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;else
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This looks pretty similar to the interface that ActiveRecord gives
us. If we go back to that list of benefits that repositories are
supposed to confer, it&#x27;s not immediately obvious that this
implementation is really going to give us any of those, except
possibly the ability to swap database implementations.&lt;&#x2F;p&gt;
&lt;p&gt;But what are we to do instead? Well, as it turns out waiting a few
days provided an answer. Over the weekend one of the Craftsmen at 8th
Light took the initiative to toss our codebase headfirst into a
slightly different repository implementation. This was a tricky
prospect for a codebase that was fairly coupled to the use of
ActiveRecord, but once we got everything figured out we ended up with
something that looked sort of like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;module &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8000;&quot;&gt;Repository
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;RepositoryBase
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;initialize&lt;&#x2F;span&gt;&lt;span&gt;(db)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;@db &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; db
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;create&lt;&#x2F;span&gt;&lt;span&gt;(attributes)
&lt;&#x2F;span&gt;&lt;span&gt;      convert(repository.create(attributes))
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;find_by_id&lt;&#x2F;span&gt;&lt;span&gt;(id)
&lt;&#x2F;span&gt;&lt;span&gt;      convert(repository.find_by_id(id.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;to_i&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;all
&lt;&#x2F;span&gt;&lt;span&gt;      repository.all.map { |e| convert(e) }
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;count
&lt;&#x2F;span&gt;&lt;span&gt;      repository.all.count
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;convert&lt;&#x2F;span&gt;&lt;span&gt;(data)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;@db&lt;&#x2F;span&gt;&lt;span&gt;.adapter.convert(model_class, data)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;model_class
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;raise &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6ae;&quot;&gt;NotImplementedError
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;repository
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;raise &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6ae;&quot;&gt;NotImplementedError
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;module &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8000;&quot;&gt;Notes
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Repository &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d78d1b;&quot;&gt;Repository::RepositoryBase
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;find_all_by_user_id&lt;&#x2F;span&gt;&lt;span&gt;(user_id)
&lt;&#x2F;span&gt;&lt;span&gt;      repository.where(&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;user_id:&lt;&#x2F;span&gt;&lt;span&gt; user_id).map &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;do &lt;&#x2F;span&gt;&lt;span&gt;|note|
&lt;&#x2F;span&gt;&lt;span&gt;        convert(note)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;model_class
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Notes&lt;&#x2F;span&gt;&lt;span&gt;::Note
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;repository
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;@db&lt;&#x2F;span&gt;&lt;span&gt;.notes
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This actually looks substantially similar, and in some ways bears even
more resemblance to an ActiveRecord API.&lt;&#x2F;p&gt;
&lt;p&gt;Since it&#x27;s come up a few times, let&#x27;s consider the differences between
ActiveRecord and the Repository pattern. From the Rails Guide on
ActiveRecord:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In Active Record, objects carry both persistent data and behavior
which operates on that data. Active Record takes the opinion that
ensuring data access logic as part of the object will educate users
of that object on how to write to and read from the database.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;So the essential feature of ActiveRecord is that the Model class
represents both the domain model, and the data model. Contrast this
with one of the primary features of the Repository Pattern as
described by Eric Evans:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;[The repository] Mediates between the domain and data mapping layers
using a collection-like interface for accessing domain objects.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Instead of combining domain and data access into the same object, the
Repository gives us an explicit boundary to partition our system
on. On one side, we can hide the often significant technical
complexity of storing and retrieving data. On the other side we can be
concerned solely with domain objects and their behaviour.&lt;&#x2F;p&gt;
&lt;p&gt;So it&#x27;s not really the difference in API that we&#x27;re looking for, it&#x27;s
the architecture surrounding that API. In particular, simply by having
a separate Repository object we&#x27;ve started to achieve that separation
between data and domain. So despite the fact that our Repositories
don&#x27;t try to fully emulate a collection of domain objects we&#x27;ve
actually managed to achieve one of the primary goals of the Repository
Pattern.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;taking-it-further&quot;&gt;&lt;a href=&quot;#taking-it-further&quot; aria-label=&quot;Anchor link for: taking-it-further&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Taking it Further&lt;&#x2F;h2&gt;
&lt;p&gt;I think the most important question to ask when talking about
technical infrastructure is &amp;quot;What does it buy me?&amp;quot; In this case, what
might we be able to do now that we use repositories everywhere that
would have been difficult or impossible before? It just so happens
that one of the next features on our list was implementing users in
the system having a balance of some kind.&lt;&#x2F;p&gt;
&lt;p&gt;We decided that in the domain, this could naturally be represented by
each user having an Account. This &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Indirection&quot;&gt;indirection&lt;&#x2F;a&gt; conveniently
gives us the ability to potentially model transfers to non-User
entities. But how would we actually store the data associated with an
Account? The most obvious (and somewhat naive) way would be to store a
simple integer balance for each Account. As an ActiveRecord migration
it would probably look something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;create_table &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;accounts&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;force: :cascade &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;do &lt;&#x2F;span&gt;&lt;span&gt;|t|
&lt;&#x2F;span&gt;&lt;span&gt;  t.integer  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;balance&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;null: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span&gt;  t.integer  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;user_id&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;null: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But a common model for recording balances in the domain of accounting
is typified by double entry book-keeping. In this model the sum of all
debits and credits must always be equal, and the balance for a
particular account can be calculated by the sum of debits and credits
associated with that account. Again, in ActiveRecord that might look
something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;create_table &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;accounts&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;force: :cascade &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;do &lt;&#x2F;span&gt;&lt;span&gt;|t|
&lt;&#x2F;span&gt;&lt;span&gt;  t.integer  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;user_id&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;null: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;create_table &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;transactions&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;force: :cascade &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;do &lt;&#x2F;span&gt;&lt;span&gt;|t|
&lt;&#x2F;span&gt;&lt;span&gt;  t.integer &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;account_id&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;null: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span&gt;  t.integer &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;amount&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;null: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we&#x27;ve implemented a successful Repository, it should be possible
for us to write the Repository using the naive strategy, develop
client code that utilizes the Repository, and then transition the
Repository to use the more sophisticated transaction scheme without
making any changes to the clients.&lt;&#x2F;p&gt;
&lt;p&gt;The first key element for implementing the accounts repository is
going to be an Account domain object. Ignoring how it gets created for
the moment, here&#x27;s a basic implementation.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;module &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8000;&quot;&gt;Accounts
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Account
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;attr_reader &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:id&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:balance&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:user_id
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;deposit&lt;&#x2F;span&gt;&lt;span&gt;(amount)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;@balance &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span&gt; amount
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;transfer_to&lt;&#x2F;span&gt;&lt;span&gt;(account, amount)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;has_funds?(amount)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;raise &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;Balance too low&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;else
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;@balance &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;-=&lt;&#x2F;span&gt;&lt;span&gt; amount
&lt;&#x2F;span&gt;&lt;span&gt;        account.deposit(amount)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;has_funds?&lt;&#x2F;span&gt;&lt;span&gt;(amount)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;@balance &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;gt;=&lt;&#x2F;span&gt;&lt;span&gt; amount
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Repository &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d78d1b;&quot;&gt;Repository::RepoBase
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;create_for&lt;&#x2F;span&gt;&lt;span&gt;(user)
&lt;&#x2F;span&gt;&lt;span&gt;      account &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; create({&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;user_id:&lt;&#x2F;span&gt;&lt;span&gt; user.id})
&lt;&#x2F;span&gt;&lt;span&gt;      account
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;find_by_user&lt;&#x2F;span&gt;&lt;span&gt;(user)
&lt;&#x2F;span&gt;&lt;span&gt;      convert(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;@db&lt;&#x2F;span&gt;&lt;span&gt;.accounts.find_by_user_id(user.id))
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;model_class
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Accounts&lt;&#x2F;span&gt;&lt;span&gt;::Account
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice that this version of the account uses the same naive model of
storing a simple balance. We could rewrite this domain level code to
store a list of transactions as an array of hashes, and then collapse
the list of transactions to the new effective balance when saving the
object. So already, we can see that separating the concerns of data
storage and domain behaviour has achieved some level of isolation.&lt;&#x2F;p&gt;
&lt;p&gt;Now let&#x27;s imagine we change the database implementation so there is no
longer any &lt;code&gt;db.accounts&lt;&#x2F;code&gt; object. Instead, we have &lt;code&gt;db.transactions&lt;&#x2F;code&gt;
which has methods like &lt;code&gt;find_all_transactions_for_account_id&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Again ignoring details of how the transactions are created or saved:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;module &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8000;&quot;&gt;Accounts
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Repository &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d78d1b;&quot;&gt;Repository::RepoBase
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;create_for&lt;&#x2F;span&gt;&lt;span&gt;(user)
&lt;&#x2F;span&gt;&lt;span&gt;      account &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; create({&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;user_id:&lt;&#x2F;span&gt;&lt;span&gt; user.id})
&lt;&#x2F;span&gt;&lt;span&gt;      account
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;find_by_user&lt;&#x2F;span&gt;&lt;span&gt;(user)
&lt;&#x2F;span&gt;&lt;span&gt;      transactions &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;@db&lt;&#x2F;span&gt;&lt;span&gt;.transactions.find_by_user_id(user.id)
&lt;&#x2F;span&gt;&lt;span&gt;      balance &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; transactions.reduce(&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;) { |r,t| r &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; t.amount }
&lt;&#x2F;span&gt;&lt;span&gt;      convert({&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;user_id:&lt;&#x2F;span&gt;&lt;span&gt; user.id, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;balance:&lt;&#x2F;span&gt;&lt;span&gt; balance})
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;model_class
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f4a020;&quot;&gt;Accounts&lt;&#x2F;span&gt;&lt;span&gt;::Account
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This was a very minor change, given that under the covers data is
being stored in an entirely different manner. Even better, the change
is totally isolated to the repository. Because of the original naive
implementation of the Account domain object, some changes will need to
be made to the way it handles transfers. This may look like the
details of the data storage are leaking into the domain, but in fact
this is a data requirement bubbling up. We can&#x27;t store transactions if
we don&#x27;t record them in the first place. And realistically, we&#x27;re
probably going to need the concept of a Transaction to be added to the
domain model.&lt;&#x2F;p&gt;
&lt;p&gt;You may then find yourself wondering, &amp;quot;What value do we really get
from this separation if both sides of the boundary are going to need
to change anyhow?&amp;quot; The answer I think is two things: separation of
concerns and incremental changes. The details of how we handle
transactions in the domain layer are going to be different from the
details needed to handle storing data in the database. This separation
of concerns allows us to focus on the technical complexity of data
storage when writing that code, and to focus on the business
complexity when dealing with the domain code instead of mixing the two
together.&lt;&#x2F;p&gt;
&lt;p&gt;Second, this separation layer provides us an abstraction layer that we
can use to isolate changes to our code. Earlier I demonstrated how the
domain layer could stay the same even though storage had moved to a
transaction model. It&#x27;s not too hard to imagine changing the domain
model to track transactions using pure Ruby data structures and having
the repository still store accounts with an explicit balance.&lt;&#x2F;p&gt;
&lt;p&gt;This separation layer then gives us a nice stepping stone to move from
one implementation to the other. This stepping stone is important
because it&#x27;s a place where we should be able to stop making code
changes and have all of our tests pass. To me, being able to make real
changes in this stepwise manner is one of the hallmarks of
well-factored and decoupled code.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Estimating is Hard</title>
		<published>2015-05-26T00:00:00+00:00</published>
		<updated>2015-05-26T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/estimating-is-hard/" type="text/html"/>
		<id>https://zefira.dev/posts/estimating-is-hard/</id>
		<content type="html">&lt;p&gt;I&#x27;m coming up on the end of my first iteration at 8th Light where I
was asked to estimate how long each of my stories was going to
take. For the three stories that make up the majority of converting my
rack Tic-Tac-Toe from a multi-page vanilla HTML&#x2F;CSS app, to a SPA
(Single Page App) that uses AJAX to communicate with the server I came
up with a total of about 11 points. Given that at 8th Light we want to
be nominally doing about 9 points per week that meant that I estimated
it would take me just a touch over one iteration to complete that
transformation. But looking at it right now, I don&#x27;t think I&#x27;m on
track to meet that goal.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;Estimating is acknowledged to be hard.  The advice from &lt;em&gt;The Pragmatic
Programmer&lt;&#x2F;em&gt; acknowledges that and says that basically the only way to
get better at it is to try and estimate things and then track how
(in)accurate your estimates are. Beyond that general acknowledgement
though, I think I have some personal habits&#x2F;quirks that make my
estimates less than good.&lt;&#x2F;p&gt;
&lt;p&gt;First, I have a tendency to want to seem like I know what I&#x27;m doing,
even when I don&#x27;t. This is obviously problematic for estimation since
in it&#x27;s simplest form it might make me underestimate how long I think
something will take so I look more proficient. There&#x27;s a more
insidious way that this attitude causes me problems though. It means I
have a tendency not to ask questions, and I probably tend to bang my
head against things that aren&#x27;t working for too long before I ask for
help.&lt;&#x2F;p&gt;
&lt;p&gt;The second problem I have is reading things and ensuring I actually am
comprehending them. This is sort of related to the first problem since
I think it comes from a similar place. But at this point it&#x27;s more of
a mental habit than an explicit choice. For instance, even though I
didn&#x27;t have a short time limit to figure out my estimates, I still did
them fairly quickly and without really having a clear picture of what
work I would have to do for each story. As soon as I started
trying to implement the stories, I realized this.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-takeaway&quot;&gt;&lt;a href=&quot;#the-takeaway&quot; aria-label=&quot;Anchor link for: the-takeaway&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
The Takeaway&lt;&#x2F;h3&gt;
&lt;p&gt;I need a more systematic approach to the way I come up with
estimates. First off, I&#x27;m going to go re-read the article on it from
&lt;em&gt;The Pragmatic Programmer&lt;&#x2F;em&gt;. As I recall it has some excellent advice
that I don&#x27;t remember half well enough. Second, I think I&#x27;m going to
try to partially adopt a strategy that my co-mentor Zach suggested
when I was reviewing a code-base&#x27;s &amp;quot;viability for extension.&amp;quot; His
advice was to walk through the code while considering what it would
take to make some sort of reasonable change.&lt;&#x2F;p&gt;
&lt;p&gt;This is quite nebulous for a large code-base, since I first have to
decide what &amp;quot;a reasonable change&amp;quot; might be. But as a tool for reifying
the goals that I&#x27;m trying to estimate it should work very
nicely. Basically, all that this means is that I will actually
seriously try to think through what I would do to implement the story
I&#x27;m trying to estimate instead of just throwing a number out from my
gut feeling.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Domain Driven Design and Clojure</title>
		<published>2015-05-21T00:00:00+00:00</published>
		<updated>2015-05-21T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/domain-driven-design-and-clojure/" type="text/html"/>
		<id>https://zefira.dev/posts/domain-driven-design-and-clojure/</id>
		<content type="html">&lt;p&gt;I&#x27;ve been reading an excellent book recently: &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Domain-driven_design&quot;&gt;&lt;em&gt;Domain Driven Design&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;
by Eric Evans. I just finished the section on Entities and Value
Objects, and it&#x27;s caused me to start thinking about Clojure and the
&amp;quot;sane state management model&amp;quot; that language advocates&#x2F;enforces.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;The Clojure state model bears some strong similarities to what Evans
talks about when discussing the needs and uses for Entities and Value
Objects. Entities he says should be used to represent things where
their continuity of identity is more important than their current
value. Value Objects are the opposite, the important part of a Value
Object is the data it holds or represents, to the extent that Value
Objects with the same value are totally interchangeable.&lt;&#x2F;p&gt;
&lt;p&gt;He goes on to talk about the benefits that immutability and safe
arbitrary sharing that this interchangeability can give you.
Specifically, the relative looseness of the constraints on Value
Objects gives a system designer more freedom to implement Value
Objects in a way that has extra benefits, such as increased
performance or memory efficiency.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m just going to pull some quotes directly from
&lt;a href=&quot;http:&#x2F;&#x2F;clojure.org&#x2F;state&quot;&gt;the page on clojure.org about state&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;First, some words about identity:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;While some programs are merely large functions, e.g. compilers or
theorem provers, many others are not - they are more like working
models, and as such need to support what I&#x27;ll refer to in this
discussion as identity. By identity I mean a stable logical entity
associated with a series of different values over time. Models need
identity for the same reasons humans need identity - to represent
the world. How could it work if identities like &#x27;today&#x27; or &#x27;America&#x27;
had to represent a single constant value for all time?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;And now, values:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;So, for this discussion, an identity is an entity that has a state,
which is its value at a point in time. And a value is something that
doesn&#x27;t change. 42 doesn&#x27;t change. June 29th 2008 doesn&#x27;t
change. Points don&#x27;t move, dates don&#x27;t change, no matter what some
bad class libraries may cause you to believe. Even aggregates are
values. The set of my favorite foods doesn&#x27;t change, i.e. if I
prefer different foods in the future, that will be a different set.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Clearly Rich Hickey was thinking along the same lines as Eric
Evans. In fact, I would say that Clojure is a programming language
that is built on a firm conceptual model of the domain of
programming. I think this is one of the things that makes Clojure such
a joy to program in. Especially once you&#x27;re familiar with the
language, the standard idioms and the general layout of it&#x27;s
libraries. Everything is highly conceptually consistent. There have
been very few points where I learned something new about Clojure and
thought &amp;quot;Well that doesn&#x27;t really make sense...&amp;quot; More often when I
learn something new it fits smoothly into the mental model that I
already have about how the language works.&lt;&#x2F;p&gt;
&lt;p&gt;I guess this Domain Driven Design stuff might really work...&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Learning Rack</title>
		<published>2015-05-19T00:00:00+00:00</published>
		<updated>2015-05-19T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/learning-rack/" type="text/html"/>
		<id>https://zefira.dev/posts/learning-rack/</id>
		<content type="html">&lt;p&gt;For the past two weeks or so I&#x27;ve been grappling with trying to build
a simple HTTP front-end for my ruby Tic-Tac-Toe program. There have
been some non-technical hurdles with scheduling and other projects
demanding my time, but I&#x27;ve also spent a fair amount of time simply
struggling to put the pieces together with how the Rack libraries
work.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;Rack as a concept is exceptionally simple. Inspired by &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;dev&#x2F;peps&#x2F;pep-0333&#x2F;&quot;&gt;PEP 333&lt;&#x2F;a&gt;
which specified the Python Web Server Gateway Interface or WSGI, Rack
has come to be the de-facto way that Ruby applications interface with
web servers. Beyond the &lt;a href=&quot;http:&#x2F;&#x2F;rack.github.io&#x2F;&quot;&gt;basic concept&lt;&#x2F;a&gt;, Rack provides a set of
helper libraries. These include many useful middleware and convenience
classes for things like static file serving, sessions, and request
parsing and response generation. However, the documentation for the
classes included in Rack is pretty dismal.&lt;&#x2F;p&gt;
&lt;p&gt;For the most part it is all auto-generated documentation, but many of
the classes have only a vague description of what they do, with no
indication of how they&#x27;re meant to be used. Conspicuously absent or
good examples of configuration of middleware, especially in the
special DSL that is made available in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rack&#x2F;rack&#x2F;wiki&#x2F;%28tutorial%29-rackup-howto&quot;&gt;rackup&lt;&#x2F;a&gt; files.&lt;&#x2F;p&gt;
&lt;p&gt;Given the number of different web frameworks that are built on top of
Rack, it&#x27;s sort of shocking to me that the documentation is in this
sort of state. Though I guess it&#x27;s consistent with my general
experience of Ruby libraries as a whole.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve really worked in Ruby since I started my apprenticeship at 8th
Light, but from what I&#x27;ve seen, many Ruby libraries have awkward gaps
in their documentation. For instance, Guard is an amazing and vital
piece of a smooth Ruby TDD toolchain. But it&#x27;s documentation is
incredibly cryptic about how to properly setup a Guardfile. There are
more paragraphs about how to debug problems in your Guardfile than
what the format is!&lt;&#x2F;p&gt;
&lt;p&gt;Now documentation is hard. But over the last several years, it&#x27;s been
increasingly clear to me that &lt;a href=&quot;https:&#x2F;&#x2F;jacobian.org&#x2F;writing&#x2F;great-documentation&#x2F;&quot;&gt;good documentation&lt;&#x2F;a&gt; is one of
the most valuable assets that a software product can have, especially
an open-source one.&lt;&#x2F;p&gt;
&lt;p&gt;So then why is writing good documentation still so elusively
difficult? I know I struggle with it immensely. The majority of
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr?tab=repositories&quot;&gt;my projects&lt;&#x2F;a&gt; have little to no documentation, with the notable
exception of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;hermit&quot;&gt;Hermit&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I think there are a few reasons. First off, writing in general is
hard. It takes effort, and the will to keep re-writing and trying new
things to end up with a nicely polished piece of writing that reads
well, and communicates the author&#x27;s intent clearly and succinctly.&lt;&#x2F;p&gt;
&lt;p&gt;Another reason is that it&#x27;s much easier to polish a piece of writing
with good critical feedback from someone else. The complicating factor
for code documentation is that you need to find the right audience to
give you feedback. Often this means someone who is totally unfamiliar
with your exact software, but if it&#x27;s code documentation it probably
also can&#x27;t be your friend who only uses their computer for writing
Word documents and checking their social media.&lt;&#x2F;p&gt;
&lt;p&gt;But I think the final reason is that we don&#x27;t do it enough. Again,
like all other writing, the best way to get better at it, is simply by
writing lots and lots of documentation. Also, critically reading the
documentation that you read, and reflecting on what is helpful, and
what isn&#x27;t.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Chestnut - Annotated</title>
		<published>2015-05-10T00:00:00+00:00</published>
		<updated>2015-05-10T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/chestnut-annotated/" type="text/html"/>
		<id>https://zefira.dev/posts/chestnut-annotated/</id>
		<content type="html">&lt;h4 id=&quot;a-note-about-version-numbers&quot;&gt;&lt;a href=&quot;#a-note-about-version-numbers&quot; aria-label=&quot;Anchor link for: a-note-about-version-numbers&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
A Note about version numbers&lt;&#x2F;h4&gt;
&lt;p&gt;At the time of this writing, there were several newer versions of many
of the dependencies used in Chestnut. In particular, the ClojureScript
core team had fairly recently released a new version with
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clojure&#x2F;clojurescript&#x2F;wiki&#x2F;Running-REPLs&quot;&gt;vastly simplified REPL setup requirements&lt;&#x2F;a&gt; which
triggered changes to many of the related ClojureScript tooling
libraries (Piggieback, and Weasel especially). So PLEASE! Use the
latest version of Chestnut, or if you&#x27;re setting up your own project
then look up the latest versions on &lt;a href=&quot;http:&#x2F;&#x2F;clojars.org&#x2F;&quot;&gt;Clojars&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;on-to-the-annotating&quot;&gt;&lt;a href=&quot;#on-to-the-annotating&quot; aria-label=&quot;Anchor link for: on-to-the-annotating&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
On to the Annotating!&lt;&#x2F;h2&gt;
&lt;p&gt;As I wrote [recently][yaks], I recently dove head first into doing web
development with Clojure and Clojurescript. Along the way I learned a
whole heck of a lot about how to actually set up a &lt;a href=&quot;http:&#x2F;&#x2F;leiningen.org&#x2F;&quot;&gt;Leiningen&lt;&#x2F;a&gt;
project to support a nice workflow for such a project. However, most
of my new-found knowledge has already been put together into a very
nice package called &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;plexus&#x2F;chestnut&quot;&gt;Chestnut&lt;&#x2F;a&gt;. However, at first glance
(and second and third glance really) Chestnut projects are complex and
intimidating.&lt;&#x2F;p&gt;
&lt;p&gt;This post is an annotated walkthrough of the configuration that a new
Chestnut comes with. The best way to follow along would be to start
off by running &lt;code&gt;lein new chestnut tour&lt;&#x2F;code&gt; in shell and then exploring
the files as I talk about them.&lt;&#x2F;p&gt;
&lt;p&gt;[yaks]: {% post_url 2015-04-04-shaving-the-clojurescript-yaks %}&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;Let&#x27;s start by looking at the base directory.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;# Directories
&lt;&#x2F;span&gt;&lt;span&gt;- resources
&lt;&#x2F;span&gt;&lt;span&gt;- src
&lt;&#x2F;span&gt;&lt;span&gt;- env
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;# Files
&lt;&#x2F;span&gt;&lt;span&gt;- LICENSE
&lt;&#x2F;span&gt;&lt;span&gt;- README.md
&lt;&#x2F;span&gt;&lt;span&gt;- code_of_conduct.md
&lt;&#x2F;span&gt;&lt;span&gt;- project.clj
&lt;&#x2F;span&gt;&lt;span&gt;- Procfile
&lt;&#x2F;span&gt;&lt;span&gt;- system.properties
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you&#x27;re familiar with Clojure development at all, this should look
very familiar to you. But there a few unusual things: the &lt;code&gt;Procfile&lt;&#x2F;code&gt;
and &lt;code&gt;system.properties&lt;&#x2F;code&gt; files, and the &lt;code&gt;env&lt;&#x2F;code&gt; folder.  The &lt;code&gt;Procfile&lt;&#x2F;code&gt;
is a file for letting &lt;a href=&quot;https:&#x2F;&#x2F;www.heroku.com&#x2F;&quot;&gt;Heroku&lt;&#x2F;a&gt; know how to run your app, and the
contents of it are explained well in the
&lt;a href=&quot;https:&#x2F;&#x2F;devcenter.heroku.com&#x2F;articles&#x2F;getting-started-with-clojure#define-a-procfile&quot;&gt;Heroku guide to getting started with Clojure&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If we use the awesome [tree][tree] program to visualize some of these
directories we can see some interesting stuff. First, &lt;code&gt;src&lt;&#x2F;code&gt; looks
pretty standard for Clojure, with the addition of a second tree for
cljs files.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;src
&lt;&#x2F;span&gt;&lt;span&gt;├── clj
&lt;&#x2F;span&gt;&lt;span&gt;│   └── tour
&lt;&#x2F;span&gt;&lt;span&gt;│       └── server.clj
&lt;&#x2F;span&gt;&lt;span&gt;└── cljs
&lt;&#x2F;span&gt;&lt;span&gt;    └── tour
&lt;&#x2F;span&gt;&lt;span&gt;        └── core.cljs
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The same is true of the &lt;code&gt;test&lt;&#x2F;code&gt; folder. But what&#x27;s really interesting
is what is in that new &lt;code&gt;env&lt;&#x2F;code&gt; folder.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;env
&lt;&#x2F;span&gt;&lt;span&gt;├── dev
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── clj
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── tour
&lt;&#x2F;span&gt;&lt;span&gt;│   │       └── dev.clj
&lt;&#x2F;span&gt;&lt;span&gt;│   └── cljs
&lt;&#x2F;span&gt;&lt;span&gt;│       └── tour
&lt;&#x2F;span&gt;&lt;span&gt;│           └── main.cljs
&lt;&#x2F;span&gt;&lt;span&gt;├── prod
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── clj
&lt;&#x2F;span&gt;&lt;span&gt;│   │   └── tour
&lt;&#x2F;span&gt;&lt;span&gt;│   │       └── dev.clj
&lt;&#x2F;span&gt;&lt;span&gt;│   └── cljs
&lt;&#x2F;span&gt;&lt;span&gt;│       └── tour
&lt;&#x2F;span&gt;&lt;span&gt;│           └── main.cljs
&lt;&#x2F;span&gt;&lt;span&gt;└── test
&lt;&#x2F;span&gt;&lt;span&gt;    ├── js
&lt;&#x2F;span&gt;&lt;span&gt;    │   ├── polyfill.js
&lt;&#x2F;span&gt;&lt;span&gt;    │   └── unit-test.js
&lt;&#x2F;span&gt;&lt;span&gt;    └── unit-test.html
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What we see is that there are three top-level directories underneath
&lt;code&gt;env&lt;&#x2F;code&gt;, and below each of these we see what looks like normal Clojure
and Clojurescript source trees. Veeery, interesting.&lt;&#x2F;p&gt;
&lt;p&gt;Now let&#x27;s jump and take a look at the &lt;code&gt;project.clj&lt;&#x2F;code&gt;. This is where the
heart of the action is. The first is boring normal project meta-data,
and we&#x27;re going to skip it. The next section is interesting though.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;clojure&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clojure &quot;&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:source-paths &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;src&#x2F;clj&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:repl-options &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:timeout &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;200000&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; Defaults to 30000 (30 seconds)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#cc9495;&quot;&gt;:test-paths &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;spec&#x2F;clj&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;:repl-options&lt;&#x2F;code&gt; is straightforward. It just increases the timeout
when launching a REPL. Presumably this is because Chestnut REPL&#x27;s are
so filled with awesome that they take longer to load ;) The &lt;code&gt;*-paths&lt;&#x2F;code&gt;
options are simple too.  They just override the default place that
Leiningen looks for Clojure source and test files by default.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;N.B. The version of Chestnut I generated this with actually has a
bug, since it generated &amp;quot;spec&#x2F;clj&amp;quot; as the test path, but no &amp;quot;spec&amp;quot;
folder.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Next come the dependencies and plugins needed by this project.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;  :dependencies [[org.clojure&#x2F;clojure &amp;quot;1.6.0&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                 [org.clojure&#x2F;clojurescript &amp;quot;0.0-2511&amp;quot; :scope &amp;quot;provided&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                 [ring &amp;quot;1.3.2&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                 [ring&#x2F;ring-defaults &amp;quot;0.1.3&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                 [compojure &amp;quot;1.3.1&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                 [enlive &amp;quot;1.1.5&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                 [om &amp;quot;0.8.0-rc1&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                 [environ &amp;quot;1.0.0&amp;quot;]]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  :plugins [[lein-cljsbuild &amp;quot;1.0.3&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;            [lein-environ &amp;quot;1.0.0&amp;quot;]]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Clojure and Clojurescript are obviously necessary, and when you&#x27;re
using Clojurescript with Leiningen, you probably want the
[lein-cljsbuild][cljsbuild] plugin for compiling your
Clojurescript. &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ring-clojure&#x2F;ring#ring&quot;&gt;Ring&lt;&#x2F;a&gt; is the standard Clojure web application&#x27;s
library. &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ring-clojure&#x2F;ring-defaults#ring-defaults&quot;&gt;Ring-defaults&lt;&#x2F;a&gt; is a library for providing standard
configurations of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ring-clojure&#x2F;ring&#x2F;wiki&#x2F;Concepts#middleware&quot;&gt;Ring middleware&lt;&#x2F;a&gt;.  &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;weavejester&#x2F;compojure#compojure&quot;&gt;Compojure&lt;&#x2F;a&gt;
is a routing library built on top of Ring.&lt;&#x2F;p&gt;
&lt;sub&gt;
I&#x27;m not quite sure why the Clojurescript dependency is marked as
`provided`...
&lt;&#x2F;sub&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cgrand&#x2F;enlive#enlive-&quot;&gt;Enlive&lt;&#x2F;a&gt; is a &amp;quot;a selector-based (à la CSS) templating library
for Clojure.&amp;quot; Very cool stuff, and wildly useful for many other HTML
processing&#x2F;producing&#x2F;consuming tasks than just templating.
Unfortunately very under-documented. &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;omcljs&#x2F;om#om&quot;&gt;Om&lt;&#x2F;a&gt; is the only
Clojurescript specific dependency in the list, but it&#x27;s a pretty cool
one. It&#x27;s a Clojurescript interface to Facebook&#x27;s React.js library.&lt;&#x2F;p&gt;
&lt;p&gt;Finally we have the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;weavejester&#x2F;environ#environ&quot;&gt;Environ&lt;&#x2F;a&gt; library, and it&#x27;s associated
&lt;code&gt;lein-environ&lt;&#x2F;code&gt; plugin. As their README says:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Environ is a Clojure library for managing environment settings from
a number of different sources.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;However, it is also the basis for a lot of the really neat things that
Chestnut does.&lt;&#x2F;p&gt;
&lt;p&gt;Next up, we have some more basic configuration stuff.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;  :min-lein-version &amp;quot;2.5.0&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  :uberjar-name &amp;quot;tour.jar&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These two settings are specifically to help with deployment to Heroku
which looks for the &lt;code&gt;:min-lein-version&lt;&#x2F;code&gt; key to determine what version
of lein to build your app with. Chestnut also changes the uberjar name
so that the Procfile can specify a specific filename. Normally, the
uberjar name is derived from the project name and the current
version. However, this makes it a moving target.  Every time you bump
your version number you would have to update the Procfile to stay in
sync. This way, the uberjar always has one name and the Procfile never
needs to change.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, we have the basic cljs build configuration:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;  :cljsbuild {:builds {:app {:source-paths [&amp;quot;src&#x2F;cljs&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                             :compiler {:output-to     &amp;quot;resources&#x2F;public&#x2F;js&#x2F;app.js&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                                        :output-dir    &amp;quot;resources&#x2F;public&#x2F;js&#x2F;out&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                                        :source-map    &amp;quot;resources&#x2F;public&#x2F;js&#x2F;out.js.map&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                                        :preamble      [&amp;quot;react&#x2F;react.min.js&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                                        :optimizations :none
&lt;&#x2F;span&gt;&lt;span&gt;                                        :pretty-print  true}}}}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is remarkably similar to the configuration from the
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;emezeske&#x2F;lein-cljsbuild&#x2F;blob&#x2F;1.0.5&#x2F;example-projects&#x2F;none&#x2F;project.clj&quot;&gt;lein-cljsbuild none example project&lt;&#x2F;a&gt;, and a standard
setup to enable source-maps.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;profiles&quot;&gt;&lt;a href=&quot;#profiles&quot; aria-label=&quot;Anchor link for: profiles&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Profiles&lt;&#x2F;h3&gt;
&lt;p&gt;So far, most of what we&#x27;ve seen is fairly standard
clojure&#x2F;clojurescript configuration stuff. But one of the things that
makes Chestnut awesome is that it makes really good use of the
Leiningen profiles feature. In particular, it uses profiles to
concisely specify different clojurescript compilation settings and add
dependencies that are only needed for development. If this is the
first time you&#x27;ve heard about Leiningen profiles, you should probably
go &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;technomancy&#x2F;leiningen&#x2F;blob&#x2F;master&#x2F;doc&#x2F;PROFILES.md#profiles&quot;&gt;read about it&lt;&#x2F;a&gt;. The basic summary is this though:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can place any arbitrary key&#x2F;value pairs supported by defproject
into a given profile and they will be merged into the project map
when that profile is activated.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Let&#x27;s start with the extra &lt;code&gt;:dev&lt;&#x2F;code&gt; setups. It starts off nice and easy
just adding more clojure source and test paths and some extra
development-only dependencies.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;  :profiles {:dev {:source-paths [&amp;quot;env&#x2F;dev&#x2F;clj&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                   :test-paths [&amp;quot;test&#x2F;clj&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;                   :dependencies [[figwheel &amp;quot;0.2.1-SNAPSHOT&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                                  [figwheel-sidecar &amp;quot;0.2.1-SNAPSHOT&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                                  [com.cemerick&#x2F;piggieback &amp;quot;0.1.3&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                                  [weasel &amp;quot;0.4.2&amp;quot;]]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice that there is a similar entry under the &lt;code&gt;:uberjar&lt;&#x2F;code&gt; profile for
&lt;code&gt;:source-paths&lt;&#x2F;code&gt; but that the &lt;code&gt;:test-paths&lt;&#x2F;code&gt; are omitted (since the
uberjar is typically for distributing production code).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bhauman&#x2F;lein-figwheel#lein-figwheel&quot;&gt;Figwheel&lt;&#x2F;a&gt; is a very cool project that &amp;quot;pushes ClojureScript code
changes to the client.&amp;quot; This enables a very smooth Clojurescript
workflow. It&#x27;s so seamless in fact that in some ways it makes
Clojurescript programming &lt;em&gt;more enjoyable&lt;&#x2F;em&gt; than working with Clojure!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cemerick&#x2F;piggieback#piggieback-&quot;&gt;Piggieback&lt;&#x2F;a&gt; provides support for running a ClojureScript REPL
on top of an nREPL session. Chas goes into the reasons of why this is
a desirable thing in the README, so go check it out if you&#x27;re interested.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tomjakubowski&#x2F;weasel#weasel&quot;&gt;Weasel&lt;&#x2F;a&gt; allows your ClojureScript REPL to use
WebSockets to communicate with your chosen execution environment.
Again, their README has good information about why this might be a
thing you want.&lt;&#x2F;p&gt;
&lt;p&gt;The next two sections are pretty much just setup for Piggieback and
Figwheel:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;                   :repl-options {:init-ns tour.server
&lt;&#x2F;span&gt;&lt;span&gt;                                  :nrepl-middleware [cemerick.piggieback&#x2F;wrap-cljs-repl]}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;                   :plugins [[lein-figwheel &amp;quot;0.2.1-SNAPSHOT&amp;quot;]]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;                   :figwheel {:http-server-root &amp;quot;public&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                              :server-port 3449
&lt;&#x2F;span&gt;&lt;span&gt;                              :css-dirs [&amp;quot;resources&#x2F;public&#x2F;css&amp;quot;]}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then both the dev and uberjar profiles contain an &lt;code&gt;:env&lt;&#x2F;code&gt; map
specifying either that &lt;code&gt;:is-dev&lt;&#x2F;code&gt; is &lt;code&gt;true&lt;&#x2F;code&gt; or &lt;code&gt;false&lt;&#x2F;code&gt;. These
configurations hook into the Environ library and allow you to specify
the value of environment variables directly in the project.clj
file. This particular usage should be pretty straightforward; it&#x27;s
basically a simple switch that allows us to tell in our code whether
or not this is a dev build&#x2F;run or not.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;                   :env {:is-dev true}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The only thing remaining in the dev profile now is the cljsbuild test
configuration. Though once again, notice that there is the small
addition of the &lt;code&gt;env&#x2F;dev&#x2F;cljs&lt;&#x2F;code&gt; path as a source for our previosly
configured &lt;code&gt;app&lt;&#x2F;code&gt; ClojureScript build.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;                   :cljsbuild {:test-commands { &amp;quot;test&amp;quot; [&amp;quot;phantomjs&amp;quot; &amp;quot;env&#x2F;test&#x2F;js&#x2F;unit-test.js&amp;quot; &amp;quot;env&#x2F;test&#x2F;unit-test.html&amp;quot;] }
&lt;&#x2F;span&gt;&lt;span&gt;                               :builds {:app {:source-paths [&amp;quot;env&#x2F;dev&#x2F;cljs&amp;quot;]}
&lt;&#x2F;span&gt;&lt;span&gt;                                        :test {:source-paths [&amp;quot;src&#x2F;cljs&amp;quot; &amp;quot;test&#x2F;cljs&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                                               :compiler {:output-to     &amp;quot;resources&#x2F;public&#x2F;js&#x2F;app_test.js&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                                                          :output-dir    &amp;quot;resources&#x2F;public&#x2F;js&#x2F;test&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                                                          :source-map    &amp;quot;resources&#x2F;public&#x2F;js&#x2F;test.js.map&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                                                          :preamble      [&amp;quot;react&#x2F;react.min.js&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                                                          :optimizations :whitespace
&lt;&#x2F;span&gt;&lt;span&gt;                                                          :pretty-print  false}}}}}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Compared to the &lt;code&gt;:dev&lt;&#x2F;code&gt; profile, the &lt;code&gt;:uberjar&lt;&#x2F;code&gt; is quite simple:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;             :uberjar {:source-paths [&amp;quot;env&#x2F;prod&#x2F;clj&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                       :hooks [leiningen.cljsbuild]
&lt;&#x2F;span&gt;&lt;span&gt;                       :env {:production true}
&lt;&#x2F;span&gt;&lt;span&gt;                       :omit-source true
&lt;&#x2F;span&gt;&lt;span&gt;                       :aot :all
&lt;&#x2F;span&gt;&lt;span&gt;                       :cljsbuild {:builds {:app
&lt;&#x2F;span&gt;&lt;span&gt;                                            {:source-paths [&amp;quot;env&#x2F;prod&#x2F;cljs&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;                                             :compiler
&lt;&#x2F;span&gt;&lt;span&gt;                                             {:optimizations :advanced
&lt;&#x2F;span&gt;&lt;span&gt;                                              :pretty-print false}}}}}})
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The main difference is the addition of three pieces of configuration
that make this a true production build. The &lt;code&gt;:hooks&lt;&#x2F;code&gt; option causes
leiningen to run the &lt;code&gt;leiningen.cljsbuild&#x2F;activate&lt;&#x2F;code&gt; function to let it
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;technomancy&#x2F;leiningen&#x2F;blob&#x2F;master&#x2F;doc&#x2F;PLUGINS.md#hooks&quot;&gt;hook into the defualt Leiningen tasks&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Then &lt;code&gt;:omit-source&lt;&#x2F;code&gt; simply directs leiningen not to include the
clojure source files in the resulting uberjar, and &lt;code&gt;:aot :all&lt;&#x2F;code&gt; causes
the Clojure compiler to &lt;a href=&quot;http:&#x2F;&#x2F;clojure.org&#x2F;compilation&quot;&gt;Ahead-of-time compile&lt;&#x2F;a&gt; all your clojure
code. The idea behind both these configs is to make your final uberjar
as lean and performant as possible, at the expense of some (probably
not needed) flexibility.&lt;&#x2F;p&gt;
&lt;p&gt;So that&#x27;s it for Chestnut&#x27;s &lt;code&gt;project.clj&lt;&#x2F;code&gt;. It looks intimidating at
first, but in the end it is quite approachable when you break it down
into it&#x27;s component pieces.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Testing and the Structures of Learning Environments</title>
		<published>2015-05-06T00:00:00+00:00</published>
		<updated>2015-05-06T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/testing-and-the-structures-of-learning-environments/" type="text/html"/>
		<id>https://zefira.dev/posts/testing-and-the-structures-of-learning-environments/</id>
		<content type="html">&lt;p&gt;I&#x27;ve been fortunate this last year in getting to spend time in several
radically different learning environments in a relatively short span
of time. These experiences have gotten me thinking about the relative
pros and cons and about how I respond to the amount of structure that
environment offers.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;h3 id=&quot;the-university&quot;&gt;&lt;a href=&quot;#the-university&quot; aria-label=&quot;Anchor link for: the-university&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
The University&lt;&#x2F;h3&gt;
&lt;p&gt;Okay, let&#x27;s start off with the most structured of all, the
university. &amp;quot;formal education&amp;quot; is certainly the most structured of all
the environments I&#x27;ve been in recently. Apart from the lower-levels of
the same system, I&#x27;m having a hard time of thinking of a more
structured type of learning. I&#x27;ve written before quite extensively
about specific problems I have with the established school system, so
I&#x27;ll just leave it at that. However, university courses are highly
structured. They are actually required to by the nature of the
system. Even Fairhaven College, a place which essentially strives for
less structure only achieves that, less structure.&lt;&#x2F;p&gt;
&lt;p&gt;An excellent symbol (and indeed, a representation) of that structure
is the course syllabus. Contained in that one document are supposed to
be all the expectations and requirements for &amp;quot;doing well&amp;quot; in the
class. I noticed something towards the end of my college career. These
documents started getting more formulaic. In fact, they seem to be
approaching the type of jargon-ified meanings as &amp;quot;lawyer-ese.&amp;quot; For
instance, my university had a policy that no assignments could be
given to students during &amp;quot;dead week&amp;quot; - the week before finals -
&lt;em&gt;unless&lt;&#x2F;em&gt; the teacher had mentioned that it was possible in the
syllabus.&lt;&#x2F;p&gt;
&lt;p&gt;Because of this, many professors simply had a clause in their &amp;quot;stock&amp;quot;
syllabus that mentioned that there might be assignments due during
dead week, just to reserve the option. First of all, I have a problem
with a document that requires so much boilerplate that there can be a
&amp;quot;stock&amp;quot; version of it. Second, the system of rules and requirements
that caused teachers to always include a certain statement in the
syllabus regardless of their plans for the class, made the whole
system into a game, pitting students against each other, and often
also into opposition with their professors.&lt;&#x2F;p&gt;
&lt;p&gt;I resisted playing this game for a long time (most of my life
actually). After taking two years off from school when my mother fell
ill, I came back with a conviction that this game was a necessary evil
that I needed to play, and play well. So I did. I got excellent grades
in my last several quarters at Western in all of my classes, despite
taking heavy credit loads of all difficult classes. But I didn&#x27;t learn
as much.&lt;&#x2F;p&gt;
&lt;p&gt;My normal method of doing school appears somewhat lackadaisical
compared to the studious diligence of many &amp;quot;good&amp;quot; students. But part
of the reason for this is that I tend to follow my interests, and go
well beyond what is being asked of me by the teacher. A classic
example was a paper I needed to write for a history class in high
school. I needed to do research on some historical topic, but on the
way I stumbled upon some fascinating information about dolphins. I
spent most of my evening reading and learning much about dolphins, and
not researching for the paper. My high school pre-Calculus teacher
summarized my attitude towards school by bestowing an award on me at
the end of the year: &amp;quot;Highest Learning to Grade ratio.&amp;quot;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-recurse-center&quot;&gt;&lt;a href=&quot;#the-recurse-center&quot; aria-label=&quot;Anchor link for: the-recurse-center&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
The Recurse Center&lt;&#x2F;h3&gt;
&lt;p&gt;At the opposite end of the structure spectrum we have the Recurse
Center. It is often difficult to explain to people exactly why I chose
to go to the Recurse Center last fall. I usually fall back on
paraphrasing the tag line from their website:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Recurse Center is a free, self-directed, educational retreat for
people who want to get better at programming, whether they&#x27;ve been
coding for three decades or three months.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The key part of that statement for me is the &amp;quot;self-directed&amp;quot;
portion. The vast majority of what I learned during my CS degree came
from entirely self-directed exploration so it seemed like a natural
fit.&lt;&#x2F;p&gt;
&lt;p&gt;But they are serious when they say self-directed. The structure of
their environment is at a very bare minimum. About as bare as you can
get I think and still build a sense of community around a shared
experience. The structure and workings of the Recurse Center have been
written about by many of the students as well as the people who run
it. But for comparison&#x27;s sake, I want to mention the few structural
elements that make up the Recurse Center.&lt;&#x2F;p&gt;
&lt;p&gt;First, they spend a half day at the beginning of the batch with a
welcome meet-and-greet breakfast. This is followed by talks by the
founders and facilitators to &amp;quot;set the tone&amp;quot; and people&#x27;s expectations
for the batch. These mostly consist of talking about what they want
the Recurse Center to be, and the lightweight social rules that they
follow to help achieve that. After that, there are a few logistical
matters like keycards and access to the chat client, but then you are
thrown head-first into being at the Recurse Center: i.e. sitting in
room with about 60 other people, and learning about programming.&lt;&#x2F;p&gt;
&lt;p&gt;There are a few more things, like the Monday night talks by the
current resident or other interesting person, or the daily checkins
with other RC&#x27;ers. But other than that pretty much everything is up to
the participants of the batch. If people want to organize a daily
reading group you can do that. Or you can find someone interested in
pairing on a project with you. Or you can go to a short
presentation&#x2F;talk someone has decided to give.&lt;&#x2F;p&gt;
&lt;p&gt;If this sounds vague and confusing it&#x27;s because of the lack of
structure. It sounds like a platitude, but spending three months at
the Recurse Center really can be whatever you want it to be. A lot of
people take some time to adjust to this looseness, and there are
facilitators whose job is precisely that, to facilitate people in
their self-directed learning. Whether that means brain-storming about
projects to work on, or giving code review, or pairing on a
particularly difficult problem their whole job is to be available to
help RC&#x27;ers make the most of their time their. As a bonus they get to
spend their days doing their own self-directed learning.&lt;&#x2F;p&gt;
&lt;p&gt;The structure - or lack thereof - of the Recurse Center was inspired
at least in part by the unschooling movement as talked about by Grace
Llewellyn. I&#x27;ve [written before][unschoolove] about how I fell in love
with the idea of unschooling. But my time at the Recurse Center was
the first time I actually got to fully and intentionally practice
it. Three months was not long enough.&lt;&#x2F;p&gt;
&lt;p&gt;[unschoolove]: {% post_url 2014-05-06-s-and-e-part-three:-the-teenage-liberation-handbook %}&lt;&#x2F;p&gt;
&lt;p&gt;Despite the brevity of the experience, it did me a world of good. My
last year at college playing their game to the hilt sort of killed
something in me. I stopped enjoying programming, and I stopped seeking
out learning on my own as much. Killed is a rather strong word but
that&#x27;s how it felt. Maybe it would be more appropriate to say that it
simply wore me out. I had no energy, no [gumption] left to put into
anything. At the Recurse Center though, I built massive amounts of
gumption. So much so that I haven&#x27;t seriously found myself lacking it
since. If for only that reason, the Recurse Center was the perfect
antidote to my time at university. And I rediscovered my joy in
programming.&lt;&#x2F;p&gt;
&lt;p&gt;[gumption]: {% post_url 2014-05-01-s-and-e-part-two:-gumption %}&lt;&#x2F;p&gt;
&lt;h3 id=&quot;8th-light&quot;&gt;&lt;a href=&quot;#8th-light&quot; aria-label=&quot;Anchor link for: 8th-light&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
8th Light&lt;&#x2F;h3&gt;
&lt;p&gt;Now I&#x27;m an apprentice at 8th Light. I sought out 8th Light primarily
because of their apprenticeship program, and the remarkable similarity
it bore to [my own idealized conception][codeacademy] of how to teach
someone how to program.&lt;&#x2F;p&gt;
&lt;p&gt;[codeacademy]: {% post_url 2014-06-07-s-and-e-part-seven:-onward %}&lt;&#x2F;p&gt;
&lt;p&gt;It is sort of a fascinating and fortuitous coincidence that the amount
of structure here is in between that found at the Recurse Center and
in universities. Whether it is actually &amp;quot;just right&amp;quot; remains to be
seen. So far the balance between guidance and self-directed
exploration has been fairly ideal. Having weekly check-in&#x27;s with my
mentors puts a firm bound on how long I might drift without
purpose. Though I haven&#x27;t found that to be a problem here, it was
definitely something I needed to be mindful of during my time at the
Recurse Center. I also find it helpful to have a direction set for me,
with concrete and achievable tasks to mark the route.&lt;&#x2F;p&gt;
&lt;p&gt;One interesting thought I&#x27;ve had recently is an analogy between the
structure of these various learning environments and software testing.
I think that the Recurse Center is much like the undisciplined hacking
on a pet project. There may be tests, but they are impromptu and
somewhat haphazard. More projected onto the structure of the code
after completion than designed into it from the beginning. You can get
a lot done in this fashion, but it&#x27;s also easy to get lost in the
weeds (though this is largely the point as far as many RC&#x27;ers are
concerned).&lt;&#x2F;p&gt;
&lt;p&gt;A university degree program is then more like poorly executed TDD. The
tests are written first - mostly. But they are written with a mind to
&lt;em&gt;how&lt;&#x2F;em&gt; the task will be accomplished and are tightly, almost
inextricably, coupled to the implementation. They define a rigid but
currently stable and verified system. But woe betide the person who
tries to change anything, because much of the code and all of the
tests will break.&lt;&#x2F;p&gt;
&lt;p&gt;8th Light then is TDD done well. The tests are written first and they
specify the behavior of the system, not the implementation. The
desired goal is achieved through (rapid) iteration and feedback.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Iteration Two: Refactoring and Minimax</title>
		<published>2015-04-29T00:00:00+00:00</published>
		<updated>2015-04-29T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/iteration-two-refactoring-and-minimax/" type="text/html"/>
		<id>https://zefira.dev/posts/iteration-two-refactoring-and-minimax/</id>
		<content type="html">&lt;p&gt;I&#x27;m just about finished with my second iteration as an apprentice at
8th Light. Where my first iteration centered a lot around reading and
learning how TDD and Ruby work, this week I focused more on coding. I
spent most of my time just implementing the several stories of my
iteration: some minor (but important!) output tweaks, implementing a
play again loop, and adding two AI&#x27;s to the game. I also did quite a
bit of refactoring and general code cleanup.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;I spent several hours figuring out the mechanics of doing an extract
class refactoring, and then realizing that I had extracted the class
the wrong way and so the &amp;quot;container&amp;quot; class was the one being held by
it&#x27;s containee.  It turned out to be very awkward to try to invert
this relationship so I backed out the change and extracted the other
class so that the container&#x2F;containee relationship was correct. I
consulted Martin Fowler&#x27;s &lt;em&gt;Refactoring&lt;&#x2F;em&gt; book heavily here. It&#x27;s really
neat how the mechanical steps he describes are actually an incredibly
useful guide.&lt;&#x2F;p&gt;
&lt;p&gt;I noticed an interesting thing while I was refactoring. I was changing
the code so much that I started losing track of what was actually
going on. At some point, my brain just sort of gave up on trying to
hold the whole application in my head. This was an interesting
experience because usually I can hold more complexity in my head than
this Tic Tac Toe game currently has. I think this is part of the trend
I noticed that in general, when doing TDD I feel less need to hold a
lot of the complexity in my mind at once.&lt;&#x2F;p&gt;
&lt;p&gt;The slightly scary flip-side of that was that because I was doing
extract class refactorings and moving methods and such, I also ended
up moving tests around and modifying the tests a lot to keep them
working. Mucking around with them seriously decreased my confidence in
them, and thus in my confidence in the system as a whole. Clearly I
need to think more about how the test modification process goes along
with refactoring.&lt;&#x2F;p&gt;
&lt;p&gt;Another piece of functionality that took me surprisingly long to
implement was the play again functionality. The interesting part of
that process was that I wrote tests, and then wrote an implementation
that I thought was correct. The tests failed in a confusing manner and
so I assumed that the tests were incorrect. After poking around for
quite a while, firing up the debugger (&lt;a href=&quot;http:&#x2F;&#x2F;pryrepl.org&#x2F;&quot;&gt;Pry&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;deivid-rodriguez&#x2F;pry-byebug&quot;&gt;byebug&lt;&#x2F;a&gt; are
awesome!) I eventually discovered that the test was correct, and it
was even failing exactly correctly. I had simply forgotten to take
into account that once a game has been completed, one can&#x27;t just start
playing it again from the beginning. So I had to write a reset method.&lt;&#x2F;p&gt;
&lt;p&gt;On Tuesday I spent most of the day test driving my way to a perfect
AI. This was an interesting experience since it was the first time
I&#x27;ve had a really clear idea of where I wanted to go with the code
while doing TDD. For the most part I&#x27;ve been trying to stick to the
letter of the acronym and let the tests lead me to the code
organization they want.&lt;&#x2F;p&gt;
&lt;p&gt;But the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Minimax&quot;&gt;minimax&lt;&#x2F;a&gt; algorithm is well known and an established way to do
the game state-space search that is required for a perfect Tic-Tac-Toe
AI. So how does one test drive that? Apparently I am most definitely
not alone in asking this question as both my mentors were expecting
it, and my fellow apprentice working on Tic-Tac-Toe (Ari) also spent
time last week puzzling over it.&lt;&#x2F;p&gt;
&lt;p&gt;I worried about it briefly at the start of the day, but then I quickly
adopted the outlook that I&#x27;ve found to be most successful with TDD;
don&#x27;t think too much about the future. Instead, I focused on the
fundamentals. What&#x27;s the simplest case an AI needs to deal with. I
turned to the Wikipedia page on Tic-Tac-Toe and it&#x27;s bullet list of
how to be a perfect player. The most important rule is that an AI
should win immediately when it can. If that&#x27;s not possible it should
block an opponent from winning.&lt;&#x2F;p&gt;
&lt;p&gt;These two situations are very easy to detect. It only takes a slight
modification to the code pattern used for detecting if someone has
already won, and no future board states need to be taken into
account. This approach got me moving forwards, which is often the
hardest part.&lt;&#x2F;p&gt;
&lt;p&gt;Once I had some momentum I kept going by then considering simple fork
creation, the next most important move type. After pondering how this
might work, I hit upon a simple solution. A fork is just a move that
results in a board where you have two possible ways to win! This was
attractive to me for several reasons. First, it was a (relatively
small) step towards searching the state-space of the game. By looking
one move ahead I felt I was moving in the direction of minimax. And it
was simple enough that it felt doable in a single TDD step.&lt;&#x2F;p&gt;
&lt;p&gt;This worked shockingly well. Not only did my very simple fork
look-ahead detect most forks that it could create, somehow it actually
was able to produce the correct fork-blocking behavior in the first
four cases that I came up with.&lt;&#x2F;p&gt;
&lt;p&gt;I was suspicious though, and so I crafted some devious fork tests that
were designed to expose the flaw in my simple algorithm. Eventually I
did that and it became clear that something more powerful was
needed. At this point, thinking about the simplest way to do things
produced no clear results. I was already doing a minimal look-ahead
and the analysis was insufficient. It seemed that the next step would
have to be going to a minimax algorithm. Here&#x27;s basically what my
simple algorithm was at this point:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;score&lt;&#x2F;span&gt;&lt;span&gt;(node)
&lt;&#x2F;span&gt;&lt;span&gt;        get_wins(node.indexed_attack_sets).count
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;find_forks&lt;&#x2F;span&gt;&lt;span&gt;(board)
&lt;&#x2F;span&gt;&lt;span&gt;        scores &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; board.empty_spaces.map &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;do &lt;&#x2F;span&gt;&lt;span&gt;|index|
&lt;&#x2F;span&gt;&lt;span&gt;          node &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; board.speculative_move(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;X&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;index&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;          [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;index&lt;&#x2F;span&gt;&lt;span&gt;, score(node)]
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        scores.max_by { |i, s| s }.first
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;get_move&lt;&#x2F;span&gt;&lt;span&gt;(board)
&lt;&#x2F;span&gt;&lt;span&gt;        attacks &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; board.indexed_attack_sets
&lt;&#x2F;span&gt;&lt;span&gt;        win   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; get_wins(attacks).first
&lt;&#x2F;span&gt;&lt;span&gt;        block &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; get_blocks(attacks).first
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        win &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;or&lt;&#x2F;span&gt;&lt;span&gt; block &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;or&lt;&#x2F;span&gt;&lt;span&gt; find_forks(board)
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I tried to do get to minimax in several ways. First off, I actually
ended up using the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Negamax&quot;&gt;negamax&lt;&#x2F;a&gt; algorithm because it&#x27;s simpler to code
because it takes advantage of the zero-sum property of
Tic-Tac-Toe. Initially, I tried to replace my whole algorithm with
negamax right off the bat. This did not work out well. Things got
complicated and many tests were failing. So I backed out and treated
negamax as a small refactoring. Specifically I treated it as a
refactoring of the &lt;code&gt;find_forks&lt;&#x2F;code&gt; function. This worked quite well, and
suddenly all of the forks tests were passing. I then incrementally
expanded it until negamax was the only thing being used for deciding
which moves to make.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;clojure-tdd&quot;&gt;&lt;a href=&quot;#clojure-tdd&quot; aria-label=&quot;Anchor link for: clojure-tdd&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Clojure TDD&lt;&#x2F;h2&gt;
&lt;p&gt;I also spent some time pairing with both Emmanuel and Kristen on some
Clojure katas, the bowling game and coin changer respectively. This
was really fascinating for a couple of reasons. I consider myself
reasonably competent with Clojure. But I am almost totally unfamiliar
with trying to do TDD in Clojure.&lt;&#x2F;p&gt;
&lt;p&gt;The pairing that I did with both my fellow apprentices was in the
Ping-Pong style (mostly), where one of us wrote a test and the other
tried to make it pass. What was fascinating to me was that the
incremental development approach that this enforces pushed me towards
writing very non-idiomatic, highly stateful Clojure code.&lt;&#x2F;p&gt;
&lt;p&gt;After attempting the coin changer with Kristen, I was starting to
doubt my Clojure-chops and so I tried to TDD it out on my own. I ended
up arriving at a more satisfactory solution that used a stream model
of discrete state transformations. So a cleaner stateful solution.&lt;&#x2F;p&gt;
&lt;p&gt;I ended up talking about this with Emmanuel after our pairing session,
and he showed me a blog post and a screencast about doing the bowling
kata in Clojure. Both people ended up with similar solutions, which
basically involved the insight that a frame in bowling is only two
rolls when no strikes or spares are involved. In retrospect, this
seems sort of obvious, since a frame can&#x27;t be scored until all of it&#x27;s
rolls have occurred. But combining this with actually duplicating some
of the numbers from the stream of pin-counts is what leads to an
elegant Clojure solution.&lt;&#x2F;p&gt;
&lt;p&gt;Besides this key realization, I think I was also missing a critical
tool in my Clojure toolbox: custom lazy sequences. Both solutions
Emmanuel had found on the web ended up constructing a function that
produced a custom lazy sequence. This was necessary because of the
need to repeat certain elements from the stream.&lt;&#x2F;p&gt;
&lt;p&gt;But what I&#x27;m realizing now is that I think it&#x27;s difficult to test
drive recursive solutions. But maybe I&#x27;m just doing it wrong. Often
when I write recursive functions I don&#x27;t bother to write just the base
case first. I typically will just jump straight in and write both
parts at once. But now that I think about it, testing the base case of
a recursive algorithm would be really natural in TDD. You just have to
start at the simplest case.&lt;&#x2F;p&gt;
&lt;p&gt;Another thought that occurred to me about why TDD in Clojure is
harder. In Ruby or Java I have read about different design patterns
and there are established refactorings for manipulating class-based OO
code. So when I&#x27;m doing TDD in those languages I know the patterns of
it. Not patterns in the design patterns sense, but the flows of code
configurations you might say. Specifically, I&#x27;m familiar with the
intermediate stages and I can imagine them.&lt;&#x2F;p&gt;
&lt;p&gt;But the way I write functional code is somewhat different. Most of the
time, I experiment with a small piece of code in the REPL, until I&#x27;ve
produced the result I want, then I wrap it up into a function. This
process can proceed top-down where I conceive of the top-level
function first and then create the necessary pieces to make that
happen; or it can go bottom-up where I think about little pieces of
functionality in the domain I&#x27;m considering, and then start composing
those pieces to make more complex things.&lt;&#x2F;p&gt;
&lt;p&gt;In both of these styles of development, there isn&#x27;t always working
code at all times though. In particular, the interesting sort of
high level behaviors often don&#x27;t work until the whole thing comes
together at the end.&lt;&#x2F;p&gt;
&lt;p&gt;So I think I need at least two things before I can do TDD in Clojure
more effectively. I need to learn the patterns of Clojure code better,
and get more familiar with how it can be molded and changed from
simple and ill-factored to cleaner and well-factored. And second, I
need to adjust to the paradigm shift of thinking about code tests
first in a functional context.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>On Editors and their Benefits</title>
		<published>2015-04-16T00:00:00+00:00</published>
		<updated>2015-04-16T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/on-editors-and-their-benefits/" type="text/html"/>
		<id>https://zefira.dev/posts/on-editors-and-their-benefits/</id>
		<content type="html">&lt;p&gt;I&#x27;ve been using Emacs for about as long as I&#x27;ve been programming. So
that makes it nearly eight years now. I like to think that I&#x27;ve gotten
reasonably competent with it, and somewhat more importantly, I have
customized my emacs to fit my mind like a glove.&lt;&#x2F;p&gt;
&lt;p&gt;I also touch type, but I use the Dvorak keyboard layout. These two
things combine to make it so that I can write programs at a speed
close to how fast I can conceive them. This is important, not because
it means I can code faster than other people, but because it means I
can get the thoughts out of my head fast enough that they don&#x27;t slip
away.&lt;&#x2F;p&gt;
&lt;p&gt;This was brought into sharp relief for me a few days ago when I did
some pairing with my mentor Zach using his computer. You see, Zach
uses the standard QWERTY layout, and he also uses Vim.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;It seems that the accepted wisdom about pair programming is that it
works best when two people share the same computer, and swap control
of the keyboard back and forth. Some sources even recommend having two
sets of keyboard&#x2F;mouse to lower the barrier to switching even further.
In the spirit of being open to trying new things I acquiesced to
Zach&#x27;s implicit expectation that I would use his computer with QWERTY
and Vim.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s been a long time since I&#x27;ve seriously attempted to use
QWERTY. When I first taught myself to touch-type in Dvorak I tried to
maintain some proficiency with QWERTY since it is ubiquitous. But I
soon discovered that it was hard to keep both locations for keys in
muscle memory at the same time. And that&#x27;s really where efficient
touch typing requires that knowledge to reside. When you have to
consult your memory for the location of key, you&#x27;ve already lost a lot
of your speed.&lt;&#x2F;p&gt;
&lt;p&gt;Luckily for me, I could keep on typing QWERTY as I always had; that
is, by looking at the keyboard constantly and lifting my fingers high
enough off the keyboard that I could see the letters.&lt;&#x2F;p&gt;
&lt;p&gt;Muscle memory is important to my usage of Emacs too, and it builds
heavily on my Dvorak muscle memory. Emacs has a (deserved) reputation
for having a somewhat absurd number of key bindings. Trying to
remember them directly would be a monumental task. Instead, the most
commonly used key bindings migrate quickly from the realm of conscious
thought to muscle memory. I didn&#x27;t even notice this happening until I
started trying to teach a friend of mine to use Emacs. Some of the
commands that I use, I know only by their location on the keyboard.
Given that I type in Dvorak and the keys are labeled in QWERTY this
means that the actual character I&#x27;m pressing is pretty opaque.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;When is proficiency or familiarity with a tool more important than
other considerations?&lt;&#x2F;p&gt;
&lt;p&gt;First let&#x27;s look a bit at what those other considerations might
be. The first one that comes to mind is that using the same tools as
the team you&#x27;re working on can be pretty important. Or maybe there is
another tool that has much more powerful or focused facilities for the
task&#x2F;language&#x2F;domain. Or to reverse that, possibly your tool of choice
simply lacks something that a lot of other tools support. Finally, I
think a really important consideration is whether you are holding on
to your tool(s) of choice out of habit and the comfort they provide.
Let&#x27;s look at some examples of each of these.&lt;&#x2F;p&gt;
&lt;p&gt;A few years ago I was hired as an intern at Sage Bionetworks, a small
bio-tech start-up in Seattle. They happen to be an all Java shop,
and the standard editing environment there is Eclipse. At the time, I
was much less familiar with Emacs, I had never even opened Eclipse and
I didn&#x27;t know any Java.&lt;&#x2F;p&gt;
&lt;p&gt;I spent my first few days getting through the administrative details
of starting a new job. But pretty quickly I got to the point where I
needed to setup my new computer for doing development on the Sage web
platform. They had a wiki, with several different pages on the
bootstrapping process for the various different aspects of the
process. A significant portion of it was focused on getting your
Eclipse installation setup correctly, with all the right plugins and
such.&lt;&#x2F;p&gt;
&lt;p&gt;Being totally in love with Emacs at that time, I determined that I was
going to figure out how to setup Emacs as a kick-ass Java editing
environment. My mentor was grudgingly amenable to this plan of
action. I struggled with that problem for a few days, until my mentor
came back and strongly suggested that I use Eclipse. His rationale was
essentially that this was the tool that the whole team had
standardized on. Since no one else really used the command line tools
to build or test the product I would be largely on my own in getting
things to work.&lt;&#x2F;p&gt;
&lt;p&gt;I gave in, and learned to use Eclipse. I made it bearable by
installing a plugin that simulated Emacs key bindings. I learned there
were some nice things about Eclipse - the automatic versioning, the
Java refactoring tools. But I also found it to generally be a vastly
inferior tool. While Eclipse has an extensive ecosystem of plugins and
add-ons, installing them is a nightmare of clicking through GUI menus
and needing to restart possibly several times. It is also highly
customizable, with good support for key maps and visual
modifications. However, neither your personally installed add-ins nor
your configurations can be saved in a reasonable way, and there is (as
far as I know) no way to automate the setup process. So every time you
move to a new development machine, you need to go through the same
process. Or, more likely, go through a very &lt;em&gt;similar&lt;&#x2F;em&gt; process, and
end up with a subtly different dev environment.&lt;&#x2F;p&gt;
&lt;p&gt;But I did get the benefit of being able to get the advice of the other
devs on the team when something wasn&#x27;t working with my build. This
turned out to be critical since the process of getting a working (and
repeatable) build of their software was a highly non-trivial one.&lt;&#x2F;p&gt;
&lt;p&gt;When I was working with Zach last week and ended up using Vim with
QWERTY, he said something to me that reminded of my mentor&#x27;s words at
Sage. He said that a lot of people at 8th Light use Vim, and that if I
want to do a lot of pairing with people it will probably be to my
benefit to learn how to use Vim at least a little bit.&lt;&#x2F;p&gt;
&lt;p&gt;This makes more sense in an environment where pairing is actively
practiced, but the general idea behind it is basically the prospect of
being able to sit down at someone else&#x27;s computer and use it for
development at a reasonable level. I&#x27;m not sure that I agree with this
philosophy though.&lt;&#x2F;p&gt;
&lt;p&gt;One place where being able to use any given computer is key is as a
sysadmin. My college&#x27;s CS department started participating in a
national competition during my second year, the Collegiate Cyber
Defense Competition or CCDC. The competition itself basically places
several teams of students in the role of a new system administration
team for some large corporation. The system is potentially in disarray
after a poorly documented transition from a previous team and the
students task is to secure the systems while maintaining a given level
of availability for one or more different services (such as email,
databases, servers, etc.).&lt;&#x2F;p&gt;
&lt;p&gt;I was very interested in participating in the club that was preparing
for the competition because they were learning both defensive and
offensive computer security skills. But I found it difficult to work
in the context of system&#x27;s administration because I couldn&#x27;t have my
environment setup just how I wanted it. Particularly during the
competition itself, there would be no time to try and install Emacs
(which is both large in footprint and memory usage and requires a ton
of dependencies), or switch the terminal at the computer I was using
to Dvorak. Thus I found that two choices I had made years before had
effectively precluded my participation in the CCDC.&lt;&#x2F;p&gt;
&lt;p&gt;Interestingly, my choice to learn the Dvorak layout is actually what
pushed me into learning Emacs. I had just gotten to the point of
actual touch-typing with Dvorak when I decided it was time to switch
from using PythonWin to a &amp;quot;real programmer&#x27;s editor.&amp;quot; Based on what I
had been reading on the internet, that choice seemed clear: it had to
be Vim.&lt;&#x2F;p&gt;
&lt;p&gt;But I was stalled almost immediately. Vim uses the letters &#x27;h&#x27;, &#x27;j&#x27;,
&#x27;k&#x27;, and &#x27;l&#x27; for text navigation, so you don&#x27;t need to move your hand
to the arrow keys.  This is convenient for usage under QWERTY, all
four keys are on the home row and are easily accessible - without
stretching - to your right hand. But on Dvorak they are all over the
keyboard, and there is no mnemonic for telling which key does
what.&lt;&#x2F;p&gt;
&lt;p&gt;I struggled with Vim for a few days, trying to learn how I could remap
the movement keys to the same location under Dvorak as they are in
QWERTY. But I was unable to find a solution and the prospect of the
cascading key remappings was enough to drive me to look at Emacs.  By
contrast with Vim, most of the keys in Emacs have some kind of
mnemonic association. Moving forward a character is &lt;code&gt;ctrl f&lt;&#x2F;code&gt; and back
is &lt;code&gt;ctrl b&lt;&#x2F;code&gt;. Down one line is &lt;code&gt;ctrl n&lt;&#x2F;code&gt; and up is &lt;code&gt;ctrl p&lt;&#x2F;code&gt; for next and
previous. Not only that, but part of the very philosophy of Emacs is
easy customization, up to and including remapping every key on your
keyboard to do something different. More importantly, that philosophy
of customization is embedded in the Emacs community.&lt;&#x2F;p&gt;
&lt;p&gt;The seemingly simple choice of learning to type in Dvorak turned out
to be a key decision in my life as a programmer. It cut off certain
possibilities like learning to use Vim, and presents certain
challenges for pair programming, particularly in the quick
back-and-forth style where two people use the same computer. I have
also found that using Emacs appears to be the less common of the two,
and this is also limiting and isolating to some degree.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s the thing though, I &lt;em&gt;like&lt;&#x2F;em&gt; using Emacs; and typing in Dvorak
feels good to my fingers. So I&#x27;m a little bit stuck. I want to be
agreeable and able to collaborate and pair program with others
easily. But I also really like the tools that I use. They fit me. So
what do I do?&lt;&#x2F;p&gt;
&lt;p&gt;One possibility is to use more tools to overcome some of my
difficulties with pairing. Specifically, using a lightweight version
control system (like git) and a free code hosting site (like, say,
Github) you can arrange a style of pairing where two people work on
the same code, but each using their own device and tools and
setup. Pairing is the same during the actual coding process with
whatever Driver&#x2F;Navigator or other dynamic you want to use. The
difference comes when you swap. Instead of simply sliding the keyboard
across to your partner, you commit, and push to your central
repository. Your partner then pulls down the latest code and starts
working on their machine. This is certainly a bit more work than just
handing off the keyboard, so it may not be suitable to very rapid
hand-offs. But I haven&#x27;t found it to be overly onerous so far.&lt;&#x2F;p&gt;
&lt;p&gt;Another solution would be for me to maintain some skill at QWERTY and
Vim specifically for facilitating pairing. While more work for me
personally, it has the benefit of not requiring a new pairing
workflow. But this idea worries me a bit.&lt;&#x2F;p&gt;
&lt;p&gt;The human brain is &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Neuroplasticity&quot;&gt;amazingly flexible&lt;&#x2F;a&gt;. My favorite
personal example of this is related to video games and how we control
them. Every first-person style game has at least one key setting in
the control options: whether the way you look upwards is by moving the
mouse or tilting the control stick upwards (usually known as &amp;quot;default&amp;quot;
or &amp;quot;normal&amp;quot;), or whether this mapping is &amp;quot;inverted&amp;quot; i.e. tilting up
looks down and tilting down looks up. My best friend and I have played
a lot of Halo together in our day. For a long time one of our favorite
pastimes was playing through Halo 2 levels on Legendary difficulty,
often with skulls active. Here&#x27;s the thing though: he plays default,
and I play inverted.&lt;&#x2F;p&gt;
&lt;p&gt;Under most circumstances this doesn&#x27;t matter. If we&#x27;re playing
cooperatively it doesn&#x27;t matter because we both have our own
controller and thus our own setting. It only becomes an issue when we
are handing a controller back and forth. But boy is it a problem
then. Invariably we both forget to switch back at the hand-off and
there ensues a brief period of confusion and panic when the game
character doesn&#x27;t respond as our brain is wired to think it
should. What&#x27;s really fascinating though is how quickly my brain
starts to retrain itself.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve been playing games on inverted for years, possibly decades at
this point. As such you would think that my brain is very much
hardwired to expect that when I tilt the stick up, the view will move
down. And this is true. But sometimes, for one reason or another I&#x27;ll
end up playing for a short time on the default setting. What happens
is remarkable and incredibly frustrating. If I focus on trying to
remember that up means up and down means down, I can usually get to a
level that is usable - at least when I pay full attention. But as soon
as something intense happens like a bad guy jumping out from behind a
bush, my reflexes revert to inverted settings. Even more interestingly
though, when I inevitably switch my control scheme back to inverted I
am unable to fully shed the tendency towards trying to play with
default look controls.&lt;&#x2F;p&gt;
&lt;p&gt;Back to keyboard layouts and editors. In short, I&#x27;m concerned that an
attempt to learn how to use QWERTY again and to memorize Vim keyboard
shortcuts will seriously undermine my ability to use Emacs effectively.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, maybe this is just what I need. I&#x27;m also currently
trying to learn how to do Test Driven Development (TDD) and I&#x27;m
finding that a lot of the thought-habits I have around programming are
actually detrimental to doing TDD. Maybe breaking out of my
comfortable Emacs environment and using a new keyboard layout will
help me get into a totally new frame of mind and let me TDD more
effectively.&lt;&#x2F;p&gt;
&lt;p&gt;I think there is another reason to embrace the idea of learning a new
set of tools at this time though. A large part of the reason that I
wanted to do this apprenticeship with 8th Light was to learn. Learning
from others always requires some humility; at the very least you have
to be able to admit that there are things that you do not know. This
is difficult for me. But possibly, intentionally cultivating
&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Shoshin&quot;&gt;Shoshin&lt;&#x2F;a&gt; or &amp;quot;beginner&#x27;s mind&amp;quot; regarding my most basic level
of programming - how I edit my source code - will help me do it at all
levels.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the beginner&#x27;s mind there are many possibilities, in the expert&#x27;s
mind there are few. - Shunryu Suzuki&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Learning TDD</title>
		<published>2015-04-14T00:00:00+00:00</published>
		<updated>2015-04-14T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/learning-tdd/" type="text/html"/>
		<id>https://zefira.dev/posts/learning-tdd/</id>
		<content type="html">&lt;p&gt;This is my first week at 8th Light and I&#x27;ve been working on writing an
object-oriented Tic Tac Toe program.  This would be no big deal for
typically, even though I&#x27;m doing it in a language I&#x27;m unfamiliar with.&lt;&#x2F;p&gt;
&lt;p&gt;Except! I&#x27;m trying to very rigorously drive the development with
tests.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;This is a fairly new experience for me. I mean, sure, when I first
read about TDD a while ago, I got really interested and excited about
it. I played with it a little bit, and tried to do some small stuff in
it. But I quickly got overwhelmed with the difficulty of &amp;quot;How do you
even get started?&amp;quot;&lt;&#x2F;p&gt;
&lt;p&gt;Monday, I made very minimal progress. I felt stuck not really sure
where to begin, and what to do. I ended up by basically writing tests
for a simple Board data class where I could make marks, and then see
that the marks were actually set. This felt highly unimpressive as the
output of my first day.&lt;&#x2F;p&gt;
&lt;p&gt;Tuesday and Wednesday I made some more progress. The thing that helped
for most was certainly reaching out for guidance from my mentors. I
had a good conversation with Brian. Despite it&#x27;s somewhat brief and
vague nature it actually was very helpful. And I did some pairing with
Zach that really helped on the Ruby comfortability front. Just seeing
how someone who knows how to use Ruby approaches things made me feel
more confident and grounded in the language.&lt;&#x2F;p&gt;
&lt;p&gt;I also did quite a bit of Googling and reading about Ruby concepts and
paradigms. There wasn&#x27;t anything really specific that I was looking
for, I was just trying to absorb some of the context of the community
by seeing what is talked about and the sorts of code snippets that are
out there. To an outside observer this probably seemed mostly like
procrastinating. To be fair, I sort of judged it that way myself.&lt;&#x2F;p&gt;
&lt;p&gt;The thing is though, in all my professional software development work,
I&#x27;ve noticed that whenever I end up procrastinating and sort of
&amp;quot;working around&amp;quot; a difficulty I&#x27;m having a peculiar thing happens. If
I try to force myself to face it head on and work at it, nothing
really good comes out of it. Often I just end up feeling stuck and
then I&#x27;m really unproductive, just staring at the keyboard.&lt;&#x2F;p&gt;
&lt;p&gt;But I find if I just relax into the procrastination, and try to stay
working on related things, that eventually everything sort of gels in
my mind, and then when I come back to the &amp;quot;hard&amp;quot; thing I&#x27;m usually
able to make some useful headway.&lt;&#x2F;p&gt;
&lt;p&gt;Today was that day for TDD in Ruby; I felt like everything sort of
came together. I came into work determined not to &amp;quot;procrastinate&amp;quot; like
I did for much of yesterday. I started off by starting to test drive a
Console or display class. But I quickly realized that this would just
be a thin wrapper on top of the IO class that already exists in Ruby!
So I went back to implementing my game class, and used mocks to
replace an instance of an IO class.&lt;&#x2F;p&gt;
&lt;p&gt;From there I got into a very nice flow. Even the tricky nature of
testing the main game loop didn&#x27;t seem overly difficult in my mind. By
the end of the day I had gotten to the point where I couldn&#x27;t really
think of any more functionality that would be needed to play an actual
game at the command line.&lt;&#x2F;p&gt;
&lt;p&gt;When I wired up the class to finally actually test it from end to end
and try to play a game, there were some unexpected problems. But the
basic logical structure of the game was pretty much entirely
correct. And I knew it would be, because of the tests that I wrote.&lt;&#x2F;p&gt;
&lt;p&gt;Very cool.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Shaving the Clojurescript Yak(s)</title>
		<published>2015-04-04T00:00:00+00:00</published>
		<updated>2015-04-04T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/shaving-the-clojurescript-yaks/" type="text/html"/>
		<id>https://zefira.dev/posts/shaving-the-clojurescript-yaks/</id>
		<content type="html">&lt;p&gt;About a week ago I got fed up with a &lt;a href=&quot;http:&#x2F;&#x2F;mangafox.me&#x2F;&quot;&gt;terrible website&lt;&#x2F;a&gt; that
had comics on it I wanted to read.  So I decided to write a little web
app to make the reading experience more pleasant. Since I&#x27;m an avid
&lt;a href=&quot;http:&#x2F;&#x2F;clojure.org&#x2F;&quot;&gt;Clojurian&lt;&#x2F;a&gt;, I&#x27;ve been interested in checking out
&lt;a href=&quot;http:&#x2F;&#x2F;clojure.org&#x2F;clojurescript&quot;&gt;Clojurescript&lt;&#x2F;a&gt; for doing web development, and in particular
exploring the wonderful new world of React.js wrappers available in
Clojurescript. This is the story of how I learned to setup a
Clojurescript project.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;Since I&#x27;ve been interested in Clojurescript for a while, and even
toyed with it a few times, I came into this project with at least a
fair idea of what was out there. I knew about Om, and new basically
how the Clojurescript compilation process worked. I also am vaguely
comfortable with setting up a basic Clojure web app using &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ring-clojure&#x2F;ring&quot;&gt;Ring&lt;&#x2F;a&gt;
and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;weavejester&#x2F;compojure&quot;&gt;Compojure&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I was also aware that there had been significant advances in the
Clojurescript workflow in the past few years. Most importantly I knew
about an apparently awesome Leiningen project template for
Clojure&#x2F;Clojurescript web apps called &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;plexus&#x2F;chestnut&quot;&gt;Chestnut&lt;&#x2F;a&gt;. However,
the times that I had tried to get up and running with Chestnut
previously I was totally overwhelmed by the amount of unfamiliar
code&#x2F;configuration that it produced. Quite frankly, it seemed
excessive, and quickly led to me giving up on whatever
project-of-the-moment had inspired me.&lt;&#x2F;p&gt;
&lt;p&gt;So! This time, I determined to not start with Chestnut, and instead
build up slowly from the basic Lein app template that I was already
familiar with. And so commenced roughly five full days of mostly
yak-shaving. I&#x27;m not going to try and recount it all here; just the
highlights will be more than enough.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-i-shaved-my-yak&quot;&gt;&lt;a href=&quot;#how-i-shaved-my-yak&quot; aria-label=&quot;Anchor link for: how-i-shaved-my-yak&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
How I Shaved My Yak&lt;&#x2F;h2&gt;
&lt;p&gt;I started with off with a very vanilla &lt;code&gt;lein new app comic-reader&lt;&#x2F;code&gt;. From there, I copied the basic dependencies for a
jetty&#x2F;ring&#x2F;compojure web app from my &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;url-shortener&quot;&gt;url-shortener&lt;&#x2F;a&gt;
project. I made some basic routes to make sure everything was working
correctly.&lt;&#x2F;p&gt;
&lt;p&gt;Next came adding Clojurescript into the project. This meant setuping
the &lt;code&gt;project.clj&lt;&#x2F;code&gt; to point to where the &lt;code&gt;*.cljs&lt;&#x2F;code&gt; files would live, and
then configuring the Clojurescript compiler.  Basic Clojurescript
compilation with &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;emezeske&#x2F;lein-cljsbuild&quot;&gt;lein-cljsbuild&lt;&#x2F;a&gt; is not totally trivial to
configure, especially since there are now many different options to
the Clojurescript compiler and many resources on the web have
older&#x2F;outdated configuration examples, and typically no explanation
whatsoever of why they have it configured they way they do. But
overall it wasn&#x27;t too tough. It helped significantly that I could
again copy setups I had previously found to work.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, I was sick of shaving Yaks for a moment so I went and
learned how to use &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cgrand&#x2F;enlive&quot;&gt;Enlive&lt;&#x2F;a&gt; for doing
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;swannodette&#x2F;enlive-tutorial#an-introduction-to-enlive&quot;&gt;web scraping&lt;&#x2F;a&gt;! Then, feeling refreshed, I went back to the
Yak.&lt;&#x2F;p&gt;
&lt;p&gt;I knew that I wanted the awesome &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bhauman&#x2F;lein-figwheel&quot;&gt;Figwheel&lt;&#x2F;a&gt; plugin for an awesome
(mostly) reload-less Clojurescript experience. Again, Figwheel comes
with a Lein template that I didn&#x27;t use directly. Instead, I made an
extra copy and then used it as a reference for when my configuration
based on reading the documentation didn&#x27;t work.&lt;&#x2F;p&gt;
&lt;p&gt;Next step was adding in Om, and making a basic page setup
there. Again, nothing incredibly hard. I mostly just followed the
tutorial and everything came together fairly quickly. Only maybe an
hour of struggling and cursing at my computer. Then, I decided that I
wanted to build a single-page application (SPA). So I started looking
at libraries like &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gf3&#x2F;secretary&quot;&gt;Secretary&lt;&#x2F;a&gt; and
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;r0man&#x2F;sablono&quot;&gt;Sablono&lt;&#x2F;a&gt;. Eventually, after reading several blog posts and
pages of documentation, I decided that I actually wanted to use
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;reagent-project&#x2F;reagent&quot;&gt;Reagent&lt;&#x2F;a&gt; instead of Om. Luckily I hadn&#x27;t written much actual
code before I came to that decision.&lt;&#x2F;p&gt;
&lt;p&gt;After playing with Reagent for a while, I started having difficulty
with thinking about how to use it as the basis for a SPA, especially
with in-browser routing happening, and changing the history token so
that different app states would be bookmark-able. (N.B. I&#x27;ve minimized
the explanation of this considerably. I spent a good chunk of time
wrestling with getting history integration working with Reagent before
realizing that Reagent&#x27;s flow didn&#x27;t make any damn sense to me.)&lt;&#x2F;p&gt;
&lt;p&gt;Back to the Google! After quite a lot of searching, sleeping, reading,
and searching again I found &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Day8&#x2F;re-frame&quot;&gt;re-frame&lt;&#x2F;a&gt; and it&#x27;s epic
manifesto. After reading the whole damn thing (and all of the
&amp;quot;read-this-first&amp;quot; links), I decided that I would switch from vanilla
Reagent to re-frame. Again, thank goodness I hadn&#x27;t really written any
significant code that was tightly coupled to reagent.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, most everything worked pretty nicely, but there was
some significant ugliness about. I had my Figwheel configuration
inline in the same file as my main site code, and the clojurescript
configurations for production and dev were getting quite messy. After
incrementally gaining experience with most of the gaggle of
technologies that Chestnut uses, I felt prepared to tackle their
template again. So I started using it as a reference to enhance my own
configuration.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, I started doing this when I wanted to deploy my app to
Heroku. It turns out that there are a whole raft of things that where
wrong with my configuration from Heroku&#x27;s point of view. But after
about two hours of compare&#x2F;edit&#x2F;deploy cycles, I finally managed to
deploy my app to Heroku.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;&lt;a href=&quot;#wrapping-up&quot; aria-label=&quot;Anchor link for: wrapping-up&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Wrapping Up&lt;&#x2F;h2&gt;
&lt;p&gt;To sum it all up, while this was in some ways a very frustrating
exercise (especially at times during the process!), overall it was
also a really excellent learning experience. Too often I try and
approach too many new things all at once. This often leads quickly to
getting overwhelmed by all the new-ness, and then often giving
up. It&#x27;s not a great pattern.&lt;&#x2F;p&gt;
&lt;p&gt;The longer that I practice programming, the more firmly I come to
believe that incremental, evolutions of projects and knowledge are
fundamentally more approachable, sustainable and, quite simply, more
fun!&lt;&#x2F;p&gt;
&lt;p&gt;Now I&#x27;m feeling sort of pumped to do an &amp;quot;Annotated Chestnut&amp;quot;
walkthrough of what all the various configurations in Chestnut are
doing, and why they are useful and cool.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Sane Static Site Setups</title>
		<published>2014-12-30T00:00:00+00:00</published>
		<updated>2014-12-30T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/sane-static-site-setups/" type="text/html"/>
		<id>https://zefira.dev/posts/sane-static-site-setups/</id>
		<content type="html">&lt;p&gt;During the last week of Hacker School I helped &lt;a href=&quot;http:&#x2F;&#x2F;lmontopo.github.io&#x2F;&quot;&gt;Leta&lt;&#x2F;a&gt; sort out
some issues she had with her blog setup and restore everything to
sanity. It was a lot of fun and the setup is pretty straightforward so
I thought I&#x27;d do a short write-up on what we did and why.&lt;&#x2F;p&gt;
&lt;p&gt;To be clear, this blog post is about solving the particular problem of
how to organize a statically generated site&#x2F;blog. The particulars I&#x27;m
going to discuss are for when you host the site on &lt;a href=&quot;https:&#x2F;&#x2F;pages.github.com&#x2F;&quot;&gt;Github Pages&lt;&#x2F;a&gt;
but you need to generate the site locally because you&#x27;re not using
vanilla &lt;a href=&quot;http:&#x2F;&#x2F;jekyllrb.com&#x2F;&quot;&gt;Jekyll&lt;&#x2F;a&gt; or not using Jekyll at all.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;This isn&#x27;t a tutorial about how to set up and use any particular
static site generator.  There are &lt;a href=&quot;http:&#x2F;&#x2F;jekyllrb.com&#x2F;&quot;&gt;quite&lt;&#x2F;a&gt; &lt;a href=&quot;http:&#x2F;&#x2F;docs.getpelican.com&#x2F;en&#x2F;3.5.0&#x2F;&quot;&gt;a&lt;&#x2F;a&gt; &lt;a href=&quot;http:&#x2F;&#x2F;wintersmith.io&#x2F;&quot;&gt;few&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;greghendershott&#x2F;frog&quot;&gt;out&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;taylorchu&#x2F;baker&quot;&gt;there&lt;&#x2F;a&gt;, and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hugoduncan&#x2F;cl-blog-generator&quot;&gt;they&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;staticsitegenerators.net&#x2F;&quot;&gt;all&lt;&#x2F;a&gt; seem to be quite good. So pick one and
get your site setup.  You should be comfortable generating the content
of your site before worrying about what I&#x27;m describing in this post.&lt;&#x2F;p&gt;
&lt;p&gt;One of the best and worst things about using a static site generator (SSG)
is that the source for the site is fundamentally a separate thing from
the actual files that compose the site itself. The good news is that
the generated files are, well, generated. Given the source for a
site you can always regenerate the presentation files.&lt;&#x2F;p&gt;
&lt;p&gt;So clearly we want to keep the source for our site under version
control. If you&#x27;re using Github Pages then git is a natural
choice. But Github Pages also requires that the generated content of
your site be in a git repository. This leads to an un-intuitive setup.
Because the source and published files don&#x27;t actually share a common
history, it seems like they need to be stored in separate git
repositories.  However, there is a fundamental relationship between
the files that dictates that organizationally they should always be
found together.&lt;&#x2F;p&gt;
&lt;p&gt;Luckily for us, git is flexible enough to allow us to achieve both
these seemingly conflicting goals. Since the usual workflow for a git
repository simply involves &lt;code&gt;git init&lt;&#x2F;code&gt; and then edit, &lt;code&gt;add&lt;&#x2F;code&gt;,
&lt;code&gt;commit&lt;&#x2F;code&gt; cycles, it&#x27;s less well known that a git repository can
actually contain multiple independent &amp;quot;head&amp;quot; commits. Don&#x27;t worry if
that doesn&#x27;t totally make sense. The important thing is that we can
store two separate revision histories in the same git repository.&lt;&#x2F;p&gt;
&lt;p&gt;So, you have the source for a static site, and you&#x27;ve maybe written
some dummy (or real!) content for it and generated the site at least
once. Now, we want to make sure that we have a setup that will help us
preserve all of your hard work on making an awesome website.&lt;&#x2F;p&gt;
&lt;p&gt;The first thing we need to do is to make sure we have git repositories
in both the source and output directories by running &lt;code&gt;git init&lt;&#x2F;code&gt; in
both of them separately. Since most SSG&#x27;s by default use a structure
where the output folder is a subdirectory of the source folder, make
sure that you have an entry in your gitignore file so that the output
isn&#x27;t committed into the source repository. At this point we should
have two git repo&#x27;s, one that &lt;em&gt;only&lt;&#x2F;em&gt; has the site source content
(including any files need by your SSG) and one that &lt;em&gt;only&lt;&#x2F;em&gt; has the
generated version of your site.&lt;&#x2F;p&gt;
&lt;p&gt;Now for the magic trick of combining the repositories. Let&#x27;s say we
have this folder structure:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;- website&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt; - .git&#x2F;  # Git folder for source files
&lt;&#x2F;span&gt;&lt;span&gt; - ...    # Lots of awesome content files
&lt;&#x2F;span&gt;&lt;span&gt; - output&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;  - .git&#x2F; # Git folder for output files
&lt;&#x2F;span&gt;&lt;span&gt;  - ...   # The actual generated content files
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At a shell prompt in the directory &lt;code&gt;website&lt;&#x2F;code&gt;, you can run:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;git remote add output output&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;git push output master:source
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Basically, what we&#x27;re doing is setting one repository as a remote of
the other, and then pushing the content to new branch there.  Now the
&lt;code&gt;output&lt;&#x2F;code&gt; repository contains both the source and output files in
separate git branches. Pushing all the branches of this to a hosting
site means you have a complete backup of your site.&lt;&#x2F;p&gt;
&lt;p&gt;Now, the process of updating your site is a little more complicated
than the general Github Pages workflow of edit, commit and push since
you need to generate the site yourself.&lt;&#x2F;p&gt;
&lt;p&gt;First, edit your site&#x27;s content files.  Commit as necessary for your
peace of mind. Once you&#x27;re satisfied with how the content looks
(you&#x27;ve been previewing and generating the site right?), it&#x27;s time to
commit the new content to the output branch, and then push it to your
hosting location.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s basically it. It&#x27;s a simple structure, but it&#x27;s not totally
straightforward of how to get it set up, and it&#x27;s also a bit more work
to maintain. Of course there are some interesting tools out there to
help with this process. &lt;a href=&quot;http:&#x2F;&#x2F;octopress.org&#x2F;&quot;&gt;Octopress 2.0&lt;&#x2F;a&gt; tries to setup this
structure automatically for you, and provides a Rakefile for helping
to automate a lot of the normal tasks like site generation, previewing
and even deployment. &lt;a href=&quot;http:&#x2F;&#x2F;docs.getpelican.com&#x2F;en&#x2F;3.5.0&#x2F;&quot;&gt;Pelican&lt;&#x2F;a&gt; offers to generate a Makefile and&#x2F;or
a fabfile for doing the same sorts of things. Pelican also makes use
of the really neat &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;davisp&#x2F;ghp-import&quot;&gt;GHP-Import&lt;&#x2F;a&gt; project to simplify the deploying
process.&lt;&#x2F;p&gt;
&lt;p&gt;Now go forth and blog!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Getting started with LLVM and OCaml on OS X</title>
		<published>2014-12-14T00:00:00+00:00</published>
		<updated>2014-12-14T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/getting-started-with-llvm-and-ocaml-on-os-x/" type="text/html"/>
		<id>https://zefira.dev/posts/getting-started-with-llvm-and-ocaml-on-os-x/</id>
		<content type="html">&lt;p&gt;I [wrote recently][llvm-mac] about my (second) experience trying to
get started using LLVM on my Macbook. Shortly after that, I became
interested in combining my interest in LLVM with my interest OCaml. As
it turns out, this was a much easier task than I anticipated.&lt;&#x2F;p&gt;
&lt;p&gt;[llvm-mac]: {% post_url 2014-11-19-getting-started-with-llvm-on-os-x %}&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;Since my whole experiment with Vagrant was so successful for using
the C++ LLVM libraries, I immediately started doing the same thing for
my OCaml experiments. I created a &lt;code&gt;Vagrantfile&lt;&#x2F;code&gt; and started trying to
write a bash script to correctly provision an Ubuntu instance with the
requirements for the OCaml LLVM bindings.&lt;&#x2F;p&gt;
&lt;p&gt;I was stalled fairly quickly by the fact that the version of
[OPAM][opam] in the Ubuntu apt repositories is somewhat old.  Old
enough that it doesn&#x27;t want to talk to the official OPAM servers for
package updates. So I futzed and fiddled a bit, and looked around for
alternate ways to install OCaml.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually I got it figured out, and started trying to install the
OCaml bindings for LLVM. It didn&#x27;t go well. The compilation of the
llvm opam package errored almost immediately. But while I was looking
through the error messages, I noticed something interesting. The
errors were related to nonexistent paths, and the paths that the
package was expecting all started with &lt;code&gt;&#x2F;usr&#x2F;local&#x2F;Cellar&lt;&#x2F;code&gt;. For the
non brew-savvy, this is the default location that &lt;a href=&quot;http:&#x2F;&#x2F;brew.sh&#x2F;&quot;&gt;Homebrew&lt;&#x2F;a&gt;
uses for all it&#x27;s installations.&lt;&#x2F;p&gt;
&lt;p&gt;I knew that homebrew had an LLVM package because of my C++
meanderings. The error messages from OPAM on Ubuntu made me think that
the OCaml LLVM package was actually expecting to be run on a Mac, or
at least to work with a &lt;code&gt;brew install&lt;&#x2F;code&gt;ed LLVM.&lt;&#x2F;p&gt;
&lt;p&gt;So I gave it a shot. I cleaned out and re-installed my LLVM installation
with &lt;code&gt;brew rm llvm &amp;amp;&amp;amp; brew install llvm&lt;&#x2F;code&gt;. And then I simply ran &lt;code&gt;opam install llvm&lt;&#x2F;code&gt;. As far as I remember (it was a couple weeks ago now ;),
everything went off without a hitch.&lt;&#x2F;p&gt;
&lt;p&gt;&amp;lt;How was I able to validate the installation? Looked at Kaleidoscope
tutorial?&amp;gt;&lt;&#x2F;p&gt;
&lt;p&gt;Finally, I wanted to be able to use the top-level to explore the LLVM
API, but that didn&#x27;t appear to work right away. After some googling, I
found an answer on Stack Overflow (of course!) that said I had to
compile a custom version of utop with the LLVM libraries linked in.&lt;&#x2F;p&gt;
&lt;p&gt;I did that &amp;lt;describe it!! got to refigure out how I did that though&amp;gt;,
and then was able to get the wonderful utop completion stuff to work
with the totally unfamiliar LLVM bindings in OCaml.&lt;&#x2F;p&gt;
&lt;p&gt;Of course, then I needed to implement a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;postfix-ocaml&quot;&gt;language to actually compile
with LLVM&lt;&#x2F;a&gt;. And of course I still haven&#x27;t actually done
anything with LLVM...&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Getting Started with LLVM on OS X</title>
		<published>2014-11-19T00:00:00+00:00</published>
		<updated>2014-11-19T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/getting-started-with-llvm-on-os-x/" type="text/html"/>
		<id>https://zefira.dev/posts/getting-started-with-llvm-on-os-x/</id>
		<content type="html">&lt;p&gt;A few weeks ago, I decided that one of the things I wanted to tackle
during my time at Hacker School was getting familiar with the LLVM
project. To that end, myself and several other Hacker Schoolers formed
an informal group to work through the official
&lt;a href=&quot;http:&#x2F;&#x2F;llvm.org&#x2F;releases&#x2F;3.5.0&#x2F;docs&#x2F;tutorial&#x2F;index.html&quot;&gt;LLVM Kaleidoscope&lt;&#x2F;a&gt; tutorial. We made reasonable progress at
first, but as soon as we actually had to start dealing with the LLVM
tools, I started encountering problems.&lt;&#x2F;p&gt;
&lt;p&gt;Long story short, I ended up getting frustrated with the state of the
documentation surrounding LLVM and moving on to working on other less
upsetting projects. This last weekend though I ended up getting back
into it. I tried two different approaches.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;First, I decided to use a Vagrant supported VM to do my LLVM
setups. This was for two reasons: the fact that I do my development on
a Mac running OS X seems to be problematic when trying to install LLVM
in a global manner. This is because &lt;em&gt;some&lt;&#x2F;em&gt; of the LLVM tools (like
Clang) make up the default build environment on OS X. But the toolset is
insufficient if you actually want to build languages with LLVM, and
the presence of these libraries makes it... complicated to try and
install a more complete version. As Homebrew says when you try to
install LLVM via &lt;code&gt;brew install llvm&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mac OS X already provides this software and installing another
version in parallel can cause all kinds of trouble.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This is essentially the problem that I ran into a couple weeks ago
that caused me to give up on working with LLVM. This time however, I
had the insight that I wasn&#x27;t solely limited to the physical machine
that I had an the one operating system I have the space to install on
it. By using &lt;a href=&quot;https:&#x2F;&#x2F;www.vagrantup.com&#x2F;&quot;&gt;Vagrant&lt;&#x2F;a&gt; I could pretty trivially have a working Ubuntu
environment to use as my development platform for working with LLVM.&lt;&#x2F;p&gt;
&lt;p&gt;So that&#x27;s what &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;postfix-llvm&quot;&gt;I did&lt;&#x2F;a&gt;. The most interesting thing about
that repository is how I ended up provisioning my Vagrant
VM. To quote briefly from the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Provisioning#Server_provisioning&quot;&gt;Wikipedia Article&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;... provisioning is a set of actions to prepare a server with
appropriate systems, data and software, and make it ready...&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The provisioning is done via shell scripts (that&#x27;s not the interesting
part!), but instead of using &lt;code&gt;apt-get&lt;&#x2F;code&gt; to install all the software
that I required I mostly had to build them from scratch. But let&#x27;s go
through the story end to end.&lt;&#x2F;p&gt;
&lt;p&gt;First off, I did try to install all the software via &lt;code&gt;apt-get&lt;&#x2F;code&gt;. There
was some confusion for me about which version of LLVM to install. From
the reading I&#x27;d done on the [LLVM site] previously I thought that
since 3.5 has been officially released it would be considered the
stable version. However, when you install LLVM 3.5 via &lt;code&gt;apt&lt;&#x2F;code&gt; (with
&lt;code&gt;sudo apt-get install llvm-3.5&lt;&#x2F;code&gt;) the binaries don&#x27;t seem to end up
getting installed on a path location. Or rather, they are on path, but
the names are all suffixed with &lt;code&gt;-3.5&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This wasn&#x27;t really what I wanted, so I also tried installing the 3.4
packages which it turns out are also the default set of packages
installed if you &lt;code&gt;apt-get install llvm&lt;&#x2F;code&gt;. This got the right names for
the tools onto my path, so step one check. So much easier to install
than with Homebrew! Well, to install and make sure that it was available
to me anyhow.&lt;&#x2F;p&gt;
&lt;p&gt;Then, since I was going to be doing &lt;code&gt;C++&lt;&#x2F;code&gt; development, I wanted to use
&lt;a href=&quot;http:&#x2F;&#x2F;www.cmake.org&#x2F;&quot;&gt;CMake&lt;&#x2F;a&gt; as my build generator. If you&#x27;ve never used CMake but you do
&lt;code&gt;C&#x2F;C++&lt;&#x2F;code&gt; development I&#x27;d highly recommend checking it out. It allows
you to specify your build process at a very high level.  As a bonus,
it can then generate the files to process that build with &lt;a href=&quot;http:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;make&#x2F;&quot;&gt;several&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;eclipse.org&#x2F;&quot;&gt;different&lt;&#x2F;a&gt; &lt;a href=&quot;http:&#x2F;&#x2F;msdn.microsoft.com&#x2F;en-us&#x2F;vstudio&#x2F;aa718325.aspx&quot;&gt;kinds&lt;&#x2F;a&gt; of actual &lt;a href=&quot;http:&#x2F;&#x2F;www.cmake.org&#x2F;cmake&#x2F;help&#x2F;v3.0&#x2F;manual&#x2F;cmake-generators.7.html#id4&quot;&gt;build systems&lt;&#x2F;a&gt;. It&#x27;s way more
convenient than writing your own &lt;code&gt;Makefiles&lt;&#x2F;code&gt; and much more modern than
the whole &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;autoconf&#x2F;&quot;&gt;autoconf&lt;&#x2F;a&gt; system (which I can&#x27;t say much about, I&#x27;ve never
learned it).&lt;&#x2F;p&gt;
&lt;p&gt;Anyhow, CMake has another handy benefit. It has a system for
&lt;a href=&quot;http:&#x2F;&#x2F;www.cmake.org&#x2F;Wiki&#x2F;CMake:How_To_Find_Libraries&quot;&gt;finding your dependencies&lt;&#x2F;a&gt;. Not like over the internet like
&lt;a href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;1541771&#x2F;using-maven-for-c-c-projects&quot;&gt;some build systems&lt;&#x2F;a&gt;, but still it&#x27;s better than the basic
situation in C. Since CMake has actually been around for a while there
are many standard open source projects that provide the mechanics for
finding their libraries with CMake, including - handily enough - the
LLVM project.&lt;&#x2F;p&gt;
&lt;p&gt;One requirement of this system is that a &amp;quot;module file&amp;quot; be somewhere on
the CMake &lt;code&gt;modules-path&lt;&#x2F;code&gt;. For packages that support it, this should
happen when the package is installed and the locations of the critical
library and header files are actually known. Only problem is that the
CMake packages available in the Ubuntu repositories don&#x27;t actually do
this. Turns out there was a &lt;a href=&quot;https:&#x2F;&#x2F;bugs.debian.org&#x2F;cgi-bin&#x2F;bugreport.cgi?bug=735592&quot;&gt;bug report&lt;&#x2F;a&gt; early in 2014 describing the
issue. Then a long back and forth with the package maintainer (I
think) and many cases of &amp;quot;Hey, it should be fixed now!&amp;quot;, followed by a
response of &amp;quot;No, it actually still doesn&#x27;t work...&amp;quot;&lt;&#x2F;p&gt;
&lt;p&gt;Then I found the LLVM &lt;code&gt;apt&lt;&#x2F;code&gt; &lt;a href=&quot;http:&#x2F;&#x2F;llvm.org&#x2F;apt&#x2F;&quot;&gt;nightly builds page&lt;&#x2F;a&gt; which
possibly answers why LLVM 3.4 is still the default package on Ubuntu,
since the LLVM project considers 3.4 to be &amp;quot;stable&amp;quot; and 3.5 is the
&amp;quot;qualification branch.&amp;quot; This &lt;code&gt;apt&lt;&#x2F;code&gt; repository seemed like a good bet
for finding an LLVM package that would properly install the necessary
CMake files, but alas, I had no such luck.&lt;&#x2F;p&gt;
&lt;p&gt;So instead I built LLVM from scratch. This is both easier and harder
than it sounds. Building LLVM from source is a very automated process,
and the parts that aren&#x27;t automatic by default (like downloading,
checking file signatures and unpacking archives) are highly
automatable. The painful part is that VM&#x27;s are always slower than a
natively installed OS. And my poor Macbook Air takes about 45 minutes
to do a full LLVM build under the native OS X. So basically once I got
everything setup I let the LLVM build run and stopped thinking about
it except to check on it every few hours.&lt;&#x2F;p&gt;
&lt;p&gt;I had quite a few build failures mostly related to what seem
like out of memory errors in GCC. Sometimes just restarting the
compilation helped, but I also restarted Vagrant VM and gave it a full
2GB of memory which helped a lot.&lt;&#x2F;p&gt;
&lt;p&gt;Once the install finished though CMake was able to find it
immediately. As pointed out earlier, the code is up on Github. I was
surprised to discover that there is no Vagrant VM that exists for
doing LLVM development, so that&#x27;s going to go on my list of
projects. Ideally, that &lt;strong&gt;won&#x27;t&lt;&#x2F;strong&gt; involve building LLVM from source in
the provisioning stage, because of the computational issues with
VM&#x27;s. It might be an interesting excuse to learn how to build .deb
packages and make a PPA with a CMake that properly installs the
&lt;code&gt;FindLLVM.cmake&lt;&#x2F;code&gt; files...&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Demonstrating demonstrate.sh</title>
		<published>2014-10-30T00:00:00+00:00</published>
		<updated>2014-10-30T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/demonstrating-demonstrate-dot-sh/" type="text/html"/>
		<id>https://zefira.dev/posts/demonstrating-demonstrate-dot-sh/</id>
		<content type="html">&lt;p&gt;&lt;em&gt;Edit 2014&#x2F;12&#x2F;30: I ended up rewriting demonstrate in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;demonstrate.sh&quot;&gt;several&lt;&#x2F;a&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;demonstrate&quot;&gt;different&lt;&#x2F;a&gt; languages, but the implementation that I like the
best is in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;demonstrate.py&quot;&gt;python&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So, in the course of trying to prepare a presentation for this
Thursday (today!), I ended up creating a program called
&lt;code&gt;demonstrate.sh&lt;&#x2F;code&gt;. Basically, it lets you write a script, meant for an
interpreter (like bash, python, irb, coffee etc.) and then execute it
on demand.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;What do I mean by &amp;quot;on demand&amp;quot;? Well, basically it invokes the
interpreter and then reads the script file one line at a time. Then it
prints out a fake prompt based on the interpreter you specified, and
then it prints out the line of input it&#x27;s processing.  When you hit
enter, the script sends that line of input to the interpreter and it
then prints its output to the screen. Oh, there&#x27;s one little
caveat. When &lt;code&gt;demonstrate.sh&lt;&#x2F;code&gt; prints the line of output, it prints it
character by character with a small randomized delay. So it looks a
bit like you&#x27;re actually typing out the command.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s it! It&#x27;s a simple script, but it allows you to create and then
run in a repeatable way a sequence of commands that you want to
&lt;em&gt;demonstrate&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;There are some improvements I&#x27;d like to add. The ability to
recursively run demonstrate scripts inside of a demonstrate script
would be awesome. Currently because I&#x27;m doing everything in the
simplest possible way, and the script is run in the background running
demonstrate inside of a demonstrate script doesn&#x27;t work very well. I&#x27;m
actually not entirely sure why it doesn&#x27;t work, but the results are
demonstrably not what I want.&lt;&#x2F;p&gt;
&lt;p&gt;It would also be nice to make it so that you can insert arbitrary
commands to the interpreter, instead of only being able to run the
commands in the script. This is a particularly key feature since if
you just start another interpreter to run ad-hoc commands, you don&#x27;t
have the same environment. This isn&#x27;t important if your script doesn&#x27;t
contain any side-effectful things, but I think that a lot of scripts
will tend to.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, it would be really nice if the &lt;code&gt;demonstrate.sh&lt;&#x2F;code&gt; didn&#x27;t need
to fake the prompts for the interpreters. In an ideal world, those
prompts would be transparently printed directly to the screen. I&#x27;m
sure there&#x27;s a way to do it, but it probably isn&#x27;t possible&#x2F;easy in
&lt;code&gt;bash&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;When I talked to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;doy&quot;&gt;Jesse&lt;&#x2F;a&gt; about this, he asked the critical question.
Why not just record the output? My answer was essentially because I
wanted to eventually be able to run arbitrary commands in addition to
the script commands. This is sort of a weak answer, since it depends
on a feature I haven&#x27;t yet implemented!&lt;&#x2F;p&gt;
&lt;p&gt;But there&#x27;s another answer, that I discovered today when I was playing
with the classic Unix utility &lt;code&gt;script&lt;&#x2F;code&gt; that does exactly what Jesse
was talking about. The difference between recording an interaction
with &lt;code&gt;script&lt;&#x2F;code&gt; and writing a demonstrate script is this. Recording with
&lt;code&gt;script&lt;&#x2F;code&gt; is &lt;em&gt;still live coding&lt;&#x2F;em&gt;. This is especially true if you want
to use the timing feature to play it back at the same speed that it
happened at. In contrast, writing a &lt;code&gt;demonstrate&lt;&#x2F;code&gt; script is the same
as writing any regular script for the interpreter you&#x27;re
targeting. You are totally offline, and you can write and edit the
script directly, and then run it with demonstrate to make sure it does
exactly what you want.&lt;&#x2F;p&gt;
&lt;p&gt;From what I&#x27;ve been told about the early days of programming, the
difference between recording an interaction with &lt;code&gt;script&lt;&#x2F;code&gt; and writing
a &lt;code&gt;demonstrate&lt;&#x2F;code&gt; script is approximately the same as the difference
between writing programs on punch cards and writing programs in a text
editor on a computer. If you mess up while punching the card, you have
to start over from the beginning (barring awesome hacks
&lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;francesc&#x2F;status&#x2F;521602168022118400&quot;&gt;like this&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Yup, that&#x27;s it. If you&#x27;re interested, check it out
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;demonstrate.sh&quot;&gt;on Github&lt;&#x2F;a&gt;. Pull requests welcome :)&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Playing with Org-mode</title>
		<published>2014-10-27T00:00:00+00:00</published>
		<updated>2014-10-27T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/playing-with-org-mode/" type="text/html"/>
		<id>https://zefira.dev/posts/playing-with-org-mode/</id>
		<content type="html">&lt;p&gt;So, as a way to procrastinate on actually starting to write&#x2F;practice
my lightning talk for Thursday, I decided that I absolutely wanted to
make a slide show using the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;relevance&#x2F;org-html-slideshow&quot;&gt;org-html-slideshow&lt;&#x2F;a&gt;, a pretty neat piece
of Clojurescript written by those smart guys at
&lt;del&gt;Relevance&lt;&#x2F;del&gt; Cognitect.&lt;&#x2F;p&gt;
&lt;p&gt;Basically, it lets you take an outline&#x2F;document written in &lt;a href=&quot;http:&#x2F;&#x2F;orgmode.org&#x2F;&quot;&gt;Org-mode&lt;&#x2F;a&gt;
(another really cool piece of software!) and put some small
annotations in it to delimit your &amp;quot;slides&amp;quot; and then you have a
document that can be viewed as either a slideshow, or a web page. It&#x27;s
harder to explain in words than it is to observe, so here&#x27;s the
&lt;a href=&quot;&#x2F;demos&#x2F;example.html&quot;&gt;example page&lt;&#x2F;a&gt; from their github repo, and the
&lt;a href=&quot;&#x2F;demos&#x2F;example.org&quot;&gt;org-mode document&lt;&#x2F;a&gt; that produced that page.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;Now that is pretty neat. However, the workflow needed to create one of
these is sort of a pain. From the documentation on the project page,
you&#x27;re expected to create a one-off web site that has the contents of
this production folder available and then manually generate the
html document from the org-mode source. Ick.&lt;&#x2F;p&gt;
&lt;p&gt;My blog is made with &lt;a href=&quot;http:&#x2F;&#x2F;jekyllrb.com&#x2F;&quot;&gt;Jekyll&lt;&#x2F;a&gt;, which is a static site generator. None
of my posts are actually written in html, instead I write them in
&lt;a href=&quot;http:&#x2F;&#x2F;daringfireball.net&#x2F;projects&#x2F;markdown&#x2F;syntax&quot;&gt;Markdown&lt;&#x2F;a&gt;, and then Jekyll handling converts the markdown into
html. When it does this I can also cause it to be inserted into a page
template (i.e. layout). The upshot is, I can create a static site but
not have to duplicate all of the code to have a common set of header
info, navigation toolbar, nifty sidebar etc. Because only the unique
things are specified in each document, and the general boilerplate is
automatically included for me by Jekyll.&lt;&#x2F;p&gt;
&lt;p&gt;So if I&#x27;m generating html from markdown automatically with Jekyll it
feels sort of wrong to be generating html manually with an interactive
emacs command and then committing this generated html into my git
repo. It would be so much nicer if I could just get Jekyll to invoke
emacs as the translator for turning &lt;code&gt;.org&lt;&#x2F;code&gt; files into &lt;code&gt;.html&lt;&#x2F;code&gt; files.&lt;&#x2F;p&gt;
&lt;p&gt;Well, pursuing that line of thought today I worked with
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;wallyqs&quot;&gt;Waldemar Quevedo&lt;&#x2F;a&gt;. He showed me his incredible org-based workflow for
everything (he also gave an awesome lightning talk on it the first
week of Hacker School!). While it looks really cool, it&#x27;s sort
heavy-weight for what I want to do. Frankly, I&#x27;m really comfortable
writing markdown, so I&#x27;ll probably continue to write most of my posts
in it. But org-html-slideshow is exciting enough that I&#x27;d be willing
to write my presentations in Org-mode so I can utilize it.&lt;&#x2F;p&gt;
&lt;p&gt;I won&#x27;t attempt to explain Wally&#x27;s setup, but he&#x27;s got some
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;wallyqs&#x2F;org-ruby&quot;&gt;pretty&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;eggcaker&#x2F;jekyll-org&quot;&gt;cool&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;punchagan&#x2F;org-hyde&quot;&gt;stuff&lt;&#x2F;a&gt; going on. In essence
though, he uses a ruby gem to parse the org syntax and transform it
into markdown. As of this writing though, it doesn&#x27;t support the tags
feature that org-html-slideshow depends on for it&#x27;s functionality.&lt;&#x2F;p&gt;
&lt;p&gt;While showing Wally the slideshow thing got him excited to try and
integrate it into his workflow, I started poking around and looking at
how to integrate it into my site. The solution I decided on was to
make &lt;code&gt;.org&lt;&#x2F;code&gt; files a generic member of the Jekyll source files. This
means that they&#x27;ll still use a YAML frontmatter to mark that they need
to be transformed. This means that I need some way to transform a body
of org text into just the html content that it represents. Normally
when you generate an html page from org-mode, you get a complete html
page, &lt;code&gt;html&lt;&#x2F;code&gt;, &lt;code&gt;body&lt;&#x2F;code&gt; tags and all. What I needed was a way to invoke
the org-&amp;gt;html transformation using the Elisp code in org-mode from
Jekyll.&lt;&#x2F;p&gt;
&lt;p&gt;With Wally&#x27;s help, I was able to get this far towards that goal. This
is the elisp that will continuously read from the minibuffer until an
error occurs, and then transform that text using the org-&amp;gt;html backend,
and finally print out the generated html.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;lisp&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-lisp &quot;&gt;&lt;code class=&quot;language-lisp&quot; data-lang=&quot;lisp&quot;&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;progn
&lt;&#x2F;span&gt;&lt;span&gt;  (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;require&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;org)
&lt;&#x2F;span&gt;&lt;span&gt;  (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;progn
&lt;&#x2F;span&gt;&lt;span&gt;    (condition&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;nil
&lt;&#x2F;span&gt;&lt;span&gt;        (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;t
&lt;&#x2F;span&gt;&lt;span&gt;          (insert (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;read&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;string &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;      (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;error &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;    (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;buffer
&lt;&#x2F;span&gt;&lt;span&gt;     (org&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;to&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;buffer &amp;#39;html &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;*Org HTML Export*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;       &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;nil nil nil t nil
&lt;&#x2F;span&gt;&lt;span&gt;       (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;lambda &lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span&gt;)))
&lt;&#x2F;span&gt;&lt;span&gt;       (message &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;(buffer&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;))))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And this is how you invoke the transformation of a file from org to
html. The &lt;code&gt;$emacs&lt;&#x2F;code&gt; is because I use &lt;a href=&quot;http:&#x2F;&#x2F;emacsformacosx.com&#x2F;&quot;&gt;Emacs for Mac OSX&lt;&#x2F;a&gt; which means
that my emacs executable is buried inside of a mac &lt;code&gt;.app&lt;&#x2F;code&gt; file&#x2F;folder
thing. Pipe a file into this script and if it&#x27;s valid org syntax,
you&#x27;ll get the corresponding html.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;tail -n+4 hello.org &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fed6af;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt;emacs --batch --eval &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;(progn (require &amp;#39;org) (progn (condition-case nil (while t (insert (read-string &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\&amp;quot;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\&amp;quot;\\&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;n&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;)) (error nil)) (set-buffer (org-export-to-buffer &amp;#39;html &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;*Org HTML Export*&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt; nil nil nil t nil (lambda () t))) (message &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt; (buffer-string))))&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now the only thing that&#x27;s left is to write a Jekyll plugin to do this
invocation to produce the final output. &lt;del&gt;This is what I came up with
as a first attempt. Of course, it doesn&#x27;t actually work for me,
because of the dumb location of my emacs executable... Oh well, that&#x27;s
for tomorrow.&lt;&#x2F;del&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Edit 10&#x2F;28&lt;&#x2F;strong&gt;: So I spent the first half of today fixing this up.
Turned out to be more involved than I suspected. I had to evolve the
emacs lisp command enough that I actually made a separate git repo for
it. I fixed the problem of locating a proper emacs binary by deferring
to an appropriately named environment variable. I originally
implemented this shortcut by letting the user specify the location of
emacs in their &lt;code&gt;_config.yml&lt;&#x2F;code&gt;. But then I realized, this is not a
configuration that happens per-site, it&#x27;s per machine so the site
config file is totally inappropriate. It&#x27;s kind of annoying though
since if I forget to specify this environment variable then my site
generation won&#x27;t work...&lt;&#x2F;p&gt;
&lt;p&gt;Anyhow, it works and as proof I made a version of the example
presentation that is &lt;a href=&quot;&#x2F;demos&#x2F;example-plugin.html&quot;&gt;generated by my plugin&lt;&#x2F;a&gt;, not by
hand. You don&#x27;t have to take my word for it, but you will have to look
at the &lt;a href=&quot;zephyrizing&quot;&gt;git repository for this site&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;And here is the final code for my org-mode plugin generator:&lt;&#x2F;p&gt;
&lt;p&gt;{% include_code &amp;quot;Org Converter&amp;quot; lang:ruby ..&#x2F;plugins&#x2F;org_converter.rb %}&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>On the Importance of Distinguishing Between Stable and Development Documentation</title>
		<published>2014-10-26T00:00:00+00:00</published>
		<updated>2014-10-26T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/on-the-importance-of-distinguishing-between-stable-and-development-documentation/" type="text/html"/>
		<id>https://zefira.dev/posts/on-the-importance-of-distinguishing-between-stable-and-development-documentation/</id>
		<content type="html">&lt;p&gt;A few weeks ago I wrote about [Why Master Should Be Stable][stable]. I
spent most of that post explaining what had actually happened to me,
but not really talking about the fundamental underlying difficulty.
Well, now that I&#x27;ve encountered this issue again in a different
context, maybe it&#x27;s time to dive in a bit and examine what I call the
Doc&#x27;s Mismatch problem, and how it can be avoided.&lt;&#x2F;p&gt;
&lt;p&gt;[stable]: {% post_url 2014-10-07-dot-dot-dot-and-this-is-why-master-should-be-stable %}&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;As the title hints, this issue is really more about being able to
match the documentation of a project to a particular version. The
problem with Flaskr was that when you went searching for the
documentation, you most easily found the documentation for the
currently in development branch. This isn&#x27;t a problem when no major
changes have been made, but when there are major changes this becomes
an issue.&lt;&#x2F;p&gt;
&lt;p&gt;Part of the reason that I&#x27;m writing this blog post is because last
week, while I was going through the &lt;a href=&quot;http:&#x2F;&#x2F;llvm.org&quot;&gt;LLVM&lt;&#x2F;a&gt; project&#x27;s &lt;a href=&quot;http:&#x2F;&#x2F;llvm.org&#x2F;docs&#x2F;tutorial&#x2F;index.html&quot;&gt;tutorial&lt;&#x2F;a&gt; I ran
into the exact same issue! But I didn&#x27;t spot that this version
mismatch was the issue until after I had found another workaround.&lt;&#x2F;p&gt;
&lt;p&gt;Not to belabor the point, but basically the LLVM tutorial linked above
is actually the version of the tutorial written for the upcoming 3.6
release. Since there are several breaking changes to the API occurring
in this release, when you have installed LLVM 3.5 the tutorial appears
to be rather broken.&lt;&#x2F;p&gt;
&lt;p&gt;This problem is sort of ironic as the majority of open source software
out there (most definitely including all of my projects :) have
little-to-no documentation, or what there is, is hopelessly
out-of-date. In contrast, the issue that I had with both Flaskr and
LLVM was actually a case of the most easily available documentation
being TOO up-to-date.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-can-we-do-better&quot;&gt;&lt;a href=&quot;#how-can-we-do-better&quot; aria-label=&quot;Anchor link for: how-can-we-do-better&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
How can we do better?&lt;&#x2F;h3&gt;
&lt;p&gt;Let&#x27;s contrast these experiences with a project that gets it right:
&lt;a href=&quot;https:&#x2F;&#x2F;www.djangoproject.com&#x2F;&quot;&gt;Django&lt;&#x2F;a&gt;. First off, I just want to praise the Django project for
their excellent documentation in general. There is a lot of it, and it
is fairly well-written and clear. There is also a good mixture of the
&lt;a href=&quot;http:&#x2F;&#x2F;jacobian.org&#x2F;writing&#x2F;great-documentation&#x2F;what-to-write&#x2F;&quot;&gt;three types of documentation&lt;&#x2F;a&gt; that every project
needs.&lt;code&gt;&amp;lt;&#x2F;praise&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Okay, now lets look at how Django avoids the Docs Mismatch
problem. First, look at the URL for the main
&lt;a href=&quot;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;1.7&#x2F;&quot;&gt;Django Documentation page&lt;&#x2F;a&gt;:
&lt;code&gt;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;1.7&#x2F;&lt;&#x2F;code&gt;.  Notice that &lt;code&gt;1.7&lt;&#x2F;code&gt; at the
end? That indicates what version of Django these docs are for. At the
time of this writing, 1.7 is the latest &lt;strong&gt;stable&lt;&#x2F;strong&gt; release of
Django. So, right away Django is doing well. By default the link on
the Django homepage takes you to this page.  And you can bet, that
when the next stable release of Django comes out, that homepage will
be updated to point at the 1.8 version.&lt;&#x2F;p&gt;
&lt;p&gt;However, there is still more that Django is getting fundamentally
right here. By embedding the version of the documentation in the URL,
they can host multiple different versions of the documentation. And
they do! This means that if you&#x27;re forced to use an older version of
Django for whatever reason (legacy project, no install privileges
etc.) you can still go online to the Django website and find the
documentation for the version you&#x27;re using. To make this even easier,
their documentation pages all have a permanent float in the bottom
right hand corner that shows the current version of the docs that
you&#x27;re looking at, and has links to other recent versions of the
documentation.  How cool is that!&lt;&#x2F;p&gt;
&lt;p&gt;If you look at the links in that little floated element, you&#x27;ll notice
a non-numbered version is available &lt;code&gt;dev&lt;&#x2F;code&gt;. This is the documentation
for the [current development head][djangodevdoc]. More importantly,
notice that this is the equivalent of the documentation that was
easiest for me to find when dealing with both LLVM and Flaskr. But
with Django I had to specifically go looking for it. Why? Because most
people don&#x27;t want to read the docs for the development head.  And if
they do, they know it!&lt;&#x2F;p&gt;
&lt;p&gt;Django gets one more thing really right here. When you go to the dev
docs page, they automatically add a float at the top of the screen, in
an eye-catching color that effectively says: &amp;quot;These are the dev
docs. Are you sure you want to be reading them? They&#x27;re probably
different.&amp;quot;&lt;&#x2F;p&gt;
&lt;p&gt;This last feature is really the key to avoiding the Docs Mismatch
problem. The development docs are fairly rarely what people want to be
reading when they first pick up a new project. So they shouldn&#x27;t be
the easiest (or only!) documentation to find for your project.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-do-we-fix-it&quot;&gt;&lt;a href=&quot;#how-do-we-fix-it&quot; aria-label=&quot;Anchor link for: how-do-we-fix-it&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
How do we fix it?&lt;&#x2F;h3&gt;
&lt;p&gt;The ideal situation is for your documentation to be structured like
Django&#x27;s: multiple versions available, notifications when viewing the
dev version. The good news is that this is much easier to achieve
thany you might expect. &lt;a href=&quot;https:&#x2F;&#x2F;readthedocs.org&#x2F;&quot;&gt;Read The Docs&lt;&#x2F;a&gt; makes it trivial to have this
kind of setup for your open source project. In fact, Django actually
uses Read The Docs for their own documentation. I highly recommend
checking out their page and seeing just how easy it is to set up for
your own projects. Of course, once you have this awesome system the
only issue is actually writing all the awesome documentation to
populate it...&lt;&#x2F;p&gt;
&lt;h3 id=&quot;other-issues&quot;&gt;&lt;a href=&quot;#other-issues&quot; aria-label=&quot;Anchor link for: other-issues&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Other issues&lt;&#x2F;h3&gt;
&lt;p&gt;A primary problem with the Docs Mismatch issue is that the people who
notice it are typically people just wanting to use the project, not
the people developing it. This is especially problematic because these
people are also the most easily discouraged from using a project.&lt;&#x2F;p&gt;
&lt;p&gt;Another problem is that often - especially in older projects - fixing
the Docs Mismatch issue will require either access to a server, or
changes in a release deployment process or something similar. None of
these things are possible for a beginner in a project to do. This
means that the people the most motivated to fix the issue, are the
least able to do anything about it.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Adventures with Clojure macros</title>
		<published>2014-10-14T00:00:00+00:00</published>
		<updated>2014-10-14T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/adventures-with-clojure-macros/" type="text/html"/>
		<id>https://zefira.dev/posts/adventures-with-clojure-macros/</id>
		<content type="html">&lt;p&gt;So, this is the second day of my second week of &lt;a href=&quot;https:&#x2F;&#x2F;www.hackerschool.com&#x2F;&quot;&gt;Hacker School&lt;&#x2F;a&gt;. I&#x27;m
finally starting to feel like I&#x27;m getting into the
groove.&lt;&#x2F;p&gt;
&lt;p&gt;So I tackled &lt;a href=&quot;http:&#x2F;&#x2F;mitpress.mit.edu&#x2F;books&#x2F;design-concepts-programming-languages&quot;&gt;DCPL&lt;&#x2F;a&gt; in Clojure once again. I found two sort of scary
things. One, although my code was in a git repo, it wasn&#x27;t pushed to
Github. Two, there was a big hairy macro that had apparently replaced
the core of my postfix program, but it wasn&#x27;t checked in!!! Bad past
Zefira! Very bad, no good software practices...&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;Anyhow, so I cleaned things up, and pushed up to Github (it&#x27;s
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;postfix-clj&quot;&gt;here&lt;&#x2F;a&gt; FYI), and then I started playing with that macro
again. Turns out it pretty much worked. After a bit of mucking around
I managed to get it going. This quick success buoyed my spirits and I
thought, why don&#x27;t I write another... replacing repetitive code is
awesome etc.&lt;&#x2F;p&gt;
&lt;p&gt;Then there I wrote some tests, and it turns out that it didn&#x27;t
actually work. Repeat for the better part of two hours with testing
getting slowly better and my implementation getting slowly more
correct. But, there were lots of little successes throughout, so I
didn&#x27;t get discouraged, and the thrill of surmounting the difficulties
I encountered gave me a warm glow when I overcame them (macro writing
is hard! I know, because &lt;a href=&quot;http:&#x2F;&#x2F;www.paulgraham.com&#x2F;avg.html&quot;&gt;Paul Graham told me so&lt;&#x2F;a&gt; ;).&lt;&#x2F;p&gt;
&lt;p&gt;Anyhow, my success at writing this one macro made me want to write
another.  And I immediately saw an opportunity!  All of the binary
math operations for postfix are going to have the exact same form,
even with the last macro I wrote. etc. etc. about that macro, goes
pretty smooth.&lt;&#x2F;p&gt;
&lt;p&gt;Anyhow, so that went alright and now there are a bunch of tests I want
to write, just to validate that my macro is producing reasonable code
and continues to do so.&lt;&#x2F;p&gt;
&lt;p&gt;But... these tests are going to be SOOOO similar!!!  Are you thinking
what I&#x27;m thinking? Awww, yeah! Time for another macro.&lt;&#x2F;p&gt;
&lt;p&gt;So I start writing a macro to generate some simple tests for me.&lt;&#x2F;p&gt;
&lt;p&gt;All the tests have this general form:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;clojure&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clojure &quot;&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffb9d;&quot;&gt;deftest &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;subcommand-test
&lt;&#x2F;span&gt;&lt;span&gt;  (testing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;Sub command&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    (is (= (sub-cmd [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1 2&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;           [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;-1&lt;&#x2F;span&gt;&lt;span&gt;]))
&lt;&#x2F;span&gt;&lt;span&gt;    (is (= (sub-cmd [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;0 3 2&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;           [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;0 1&lt;&#x2F;span&gt;&lt;span&gt;]))
&lt;&#x2F;span&gt;&lt;span&gt;    (is (thrown-with-msg? clojure.lang.ExceptionInfo
&lt;&#x2F;span&gt;&lt;span&gt;                          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#c76f41;&quot;&gt;sub: not enough values on the stack&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                          (sub-cmd [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;])))))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So I start my macro working on that basic outline. Over the course of
another hour or so, I tweak and work it up to be this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;clojure&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clojure &quot;&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffb9d;&quot;&gt;defmacro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;defbinary-op-test &lt;&#x2F;span&gt;&lt;span&gt;[cmd-name op]
&lt;&#x2F;span&gt;&lt;span&gt;  (let [cmd-name (name cmd-name)
&lt;&#x2F;span&gt;&lt;span&gt;        fn-name  (symbol (str cmd-name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;-cmd&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;        test-args [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;        op-result (vector (apply op (reverse test-args)))]
&lt;&#x2F;span&gt;&lt;span&gt;    (prn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;test-args:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; test-args &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#ff8080;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;op result:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; op-result)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;`&lt;&#x2F;span&gt;&lt;span&gt;(testing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;(str cmd-name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt; command&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;       (is (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;fn-name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;test-args)
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;op-result))
&lt;&#x2F;span&gt;&lt;span&gt;       (is (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;fn-name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;(into [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] test-args))
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;(into [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] op-result)))
&lt;&#x2F;span&gt;&lt;span&gt;       (is (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;thrown-with-msg? clojure.lang.ExceptionInfo
&lt;&#x2F;span&gt;&lt;span&gt;                               (re-pattern &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;(str cmd-name
&lt;&#x2F;span&gt;&lt;span&gt;                                                 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;: not enough values on the stack&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;                               (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;fn-name [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]))))))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Okay, it looks like a monster.  But it&#x27;s pretty straightforward.
Since my binary ops are actually implemented by the core functions
they represent I&#x27;m not concerned with the correctness or with testing
that they work per se. I&#x27;m more concerned with the vectors going in
and coming out.  So I figure, I&#x27;ll use the same numbers for all of
them, and have the macro generate the result of actually applying the
given binary operator to the data I&#x27;ve hardcoded.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s whats going inside the &lt;code&gt;let&lt;&#x2F;code&gt; with &lt;code&gt;test-args&lt;&#x2F;code&gt; and &lt;code&gt;op-result&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;There are a couple of other tricky things I found out. For instance,
the &lt;code&gt;is&lt;&#x2F;code&gt; testing macro is looking for exactly the symbol &lt;code&gt;=&lt;&#x2F;code&gt; not for
&lt;code&gt;clojure.core&#x2F;=&lt;&#x2F;code&gt; or for &lt;code&gt;postfix.core-test&#x2F;thrown-with-msg?&lt;&#x2F;code&gt;. I know,
because those are the things &lt;code&gt;defbinary-op-test&lt;&#x2F;code&gt; produced before I put
in the unquoted-quote &lt;code&gt;~&#x27;&lt;&#x2F;code&gt; to stop the automatic namespace resolution,
as described in the &lt;a href=&quot;http:&#x2F;&#x2F;www.manning.com&#x2F;fogus2&#x2F;&quot;&gt;Joy of Clojure&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;But then, after I debugged all of these little problems, I discovered
that, though my tests were being generated syntactically correctly,
they were failing!&lt;&#x2F;p&gt;
&lt;p&gt;Now, given the way that I constructed the macro, this didn&#x27;t seem
possible.  I mean, I&#x27;m literally testing that my command, which uses
the given operator, produces the same thing as that operator.&lt;&#x2F;p&gt;
&lt;p&gt;So I dig in to make sure my macro is doing the right stuff, and pull
out &lt;code&gt;(clojure.pprint&#x2F;pprint (macroexpand-1 &#x27;(defbinary-op-test add +)))&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;which produces this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;clojure&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clojure &quot;&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span&gt;(clojure.test&#x2F;testing
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;add command&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt; (clojure.test&#x2F;is (= (add-cmd [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;]) [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;]))
&lt;&#x2F;span&gt;&lt;span&gt; (clojure.test&#x2F;is (= (add-cmd [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;0 3 1&lt;&#x2F;span&gt;&lt;span&gt;]) [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;0 3&lt;&#x2F;span&gt;&lt;span&gt;]))
&lt;&#x2F;span&gt;&lt;span&gt; (clojure.test&#x2F;is
&lt;&#x2F;span&gt;&lt;span&gt;  (thrown-with-msg?
&lt;&#x2F;span&gt;&lt;span&gt;   clojure.lang.ExceptionInfo
&lt;&#x2F;span&gt;&lt;span&gt;   (clojure.core&#x2F;re-pattern &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;add: not enough values on the stack&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;   (add-cmd [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]))))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Okay, okay everything looks good... Wait a second... Did the macro
produce the result that 3 + 1 is 3?  Okay, let&#x27;s take a closer look at
that macro again. Specifically, the two relevant portions of the let:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;test-args [3 1]
&lt;&#x2F;span&gt;&lt;span&gt;op-result (vector (apply op (reverse test-args)))]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and the part where &lt;code&gt;op-result&lt;&#x2F;code&gt; is used:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;(is (~&amp;#39;= (~fn-name ~test-args)
&lt;&#x2F;span&gt;&lt;span&gt;       ~op-result))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Okay, everthing looks pretty kosher, but to be sure, let&#x27;s try it out
in the repl, with the appropriate values filled in.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;clojure&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clojure &quot;&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span&gt;(let [op +
&lt;&#x2F;span&gt;&lt;span&gt;      test-args [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;]]
&lt;&#x2F;span&gt;&lt;span&gt;  (vector (apply op (reverse test-args))))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; =&amp;gt; [4]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s correct.  But that macroexpand clearly shows a &lt;code&gt;[3]&lt;&#x2F;code&gt; where that
&lt;code&gt;[4]&lt;&#x2F;code&gt; should be.&lt;&#x2F;p&gt;
&lt;p&gt;Okay, maybe I didn&#x27;t reproduce something correctly in the REPL.  Let&#x27;s
put some print statements in the macro before the expansion&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;clojure&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clojure &quot;&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffb9d;&quot;&gt;defmacro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;defbinary-op-test &lt;&#x2F;span&gt;&lt;span&gt;[cmd-name op]
&lt;&#x2F;span&gt;&lt;span&gt;  (let [cmd-name (name cmd-name)
&lt;&#x2F;span&gt;&lt;span&gt;        fn-name  (symbol (str cmd-name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;-cmd&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;        test-args [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;        op-result (vector (apply op (reverse test-args)))]
&lt;&#x2F;span&gt;&lt;span&gt;    (prn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;test-args:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; test-args &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;op result:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; op-result)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;`&lt;&#x2F;span&gt;&lt;span&gt;(testing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;(str cmd-name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt; command&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;       (is (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;fn-name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;test-args)
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;op-result))
&lt;&#x2F;span&gt;&lt;span&gt;       (is (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;fn-name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;(into [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] test-args))
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;(into [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] op-result)))
&lt;&#x2F;span&gt;&lt;span&gt;       (is (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;thrown-with-msg? clojure.lang.ExceptionInfo
&lt;&#x2F;span&gt;&lt;span&gt;                               (re-pattern &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;(str cmd-name
&lt;&#x2F;span&gt;&lt;span&gt;                                                 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d68686;&quot;&gt;: not enough values on the stack&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d6d6d680;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;                               (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;fn-name [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]))))))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When I reload the namespace I get this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;:reloading (postfix.core postfix.core-test)
&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;test-args:&amp;quot; [3 1] &amp;quot;op result:&amp;quot; [3]
&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;test-args:&amp;quot; [3 1] &amp;quot;op result:&amp;quot; [3]
&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;test-args:&amp;quot; [3 1] &amp;quot;op result:&amp;quot; [3]
&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;test-args:&amp;quot; [3 1] &amp;quot;op result:&amp;quot; [3]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Okay, that&#x27;s clearly what&#x27;s happening but it&#x27;s still really strange
that the &lt;code&gt;[3]&lt;&#x2F;code&gt; is showing up at all. So how about a
&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Minimal_Working_Example&quot;&gt;minimal working example&lt;&#x2F;a&gt; (or rather, not-working in this case)?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;clojure&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clojure &quot;&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffb9d;&quot;&gt;defmacro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;deftestaddproblem &lt;&#x2F;span&gt;&lt;span&gt;[op]
&lt;&#x2F;span&gt;&lt;span&gt;  (let [test-args [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;        op-result (vector (apply op (reverse test-args)))]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;`&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;test-args &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;op-result]))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then macroexpanding it:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;(clojure.pprint&#x2F;pprint (macroexpand-1 &amp;#39;(deftestaddproblem +)))
&lt;&#x2F;span&gt;&lt;span&gt;[[3 1] [3]]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Just for sanity, lets make sure it&#x27;s the right version of &lt;code&gt;+&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#393939;color:#dedede;&quot;&gt;&lt;code&gt;&lt;span&gt;(clojure.pprint&#x2F;pprint (macroexpand-1 &amp;#39;(deftestaddproblem clojure.core&#x2F;+)))
&lt;&#x2F;span&gt;&lt;span&gt;[[3 1] [3]]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What is going on!?!?!?!?! Okay, back to the REPL. This time, a raw
REPL from &lt;code&gt;lein repl&lt;&#x2F;code&gt; in my home directory.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;clojure&quot; style=&quot;background-color:#393939;color:#dedede;&quot; class=&quot;language-clojure &quot;&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span&gt;user=&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffb9d;&quot;&gt;defmacro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;dotest &lt;&#x2F;span&gt;&lt;span&gt;[op]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;   (let [test-args [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;         op-result (vector (apply op (reverse test-args)))]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;`&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;test-args &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;op-result]))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;user&#x2F;dotest
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest +)
&lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;] [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;]]
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest -)
&lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;] [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;]]
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest *)
&lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;] [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;]]
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest &#x2F;)
&lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;] [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;]]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; And without using the macro preprocessing
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (vector (apply + (reverse [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])))
&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (vector (apply - (reverse [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])))
&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;-2&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (vector (apply * (reverse [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])))
&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (vector (apply &#x2F; (reverse [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])))
&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1&#x2F;3&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; Removing more complexity...
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffb9d;&quot;&gt;defmacro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;dotest2 &lt;&#x2F;span&gt;&lt;span&gt;[op]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;   (let [test-args [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;         op-result (apply op test-args)]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;`&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;test-args &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;op-result]))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;user&#x2F;dotest2
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest2 +)
&lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest2 -)
&lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest2 *)
&lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest2 &#x2F;)
&lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; And again outside of the macro
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (apply + [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;4
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (apply - [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (apply * [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (apply &#x2F; [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; More experiments
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffb9d;&quot;&gt;defmacro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;dotest3 &lt;&#x2F;span&gt;&lt;span&gt;[]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;   (let [+-res (apply + [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;         --res (apply - [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;         *-res (apply * [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;         div-res (apply &#x2F; [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;])]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;`&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;+-res &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;--res &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;*-res &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;div-res]))
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;user&#x2F;dotest3
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest3)
&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;4 2 3 3&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; And another
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffb9d;&quot;&gt;defmacro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;dotest4 &lt;&#x2F;span&gt;&lt;span&gt;[]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;   (let [args [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;         +-res (apply + args)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;         --res (apply - args)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;         *-res (apply * args)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;         div-res (apply &#x2F; args)]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;`&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;+-res &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;--res &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;*-res &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;div-res]))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;user&#x2F;dotest4
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest4)
&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;4 2 3 3&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; This might be important...
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffb9d;&quot;&gt;defmacro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;dotest5 &lt;&#x2F;span&gt;&lt;span&gt;[op args]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;   (let [res (apply op args)]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;`&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;op &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;args &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;res]))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;user&#x2F;dotest5
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest5 + [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3 1 2&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;ArityException Wrong number of args (&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) passed to: Symbol  clojure.lang.Compiler.macroexpand1 (Compiler.java:6557)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; Or not... may just be a problem
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffb9d;&quot;&gt;defmacro &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fffd87;&quot;&gt;dotest5 &lt;&#x2F;span&gt;&lt;span&gt;[op args]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;   (let [res (apply op args)]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#_&lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;`&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;args &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;res]))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;#&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;user&#x2F;dotest5
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (dotest5 + [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1 2&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1 2&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; For sanity checking purposes, since apply can only be used with
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; functions
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (fn? +)
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (fn? -)
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (fn? *)
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (fn? &#x2F;)
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#d6d6ae;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; And as Kevin Lynagh helpfully pointed out to me, macros don&amp;#39;t
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; evaluate their arguments...  Time to re-read the section on macros
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a0cfa1;&quot;&gt;;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#87ae86;&quot;&gt; in Joy of Clojure
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (apply &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;+ [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1 2&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;user=&amp;gt; (apply (eval &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ececec;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;+) [&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;1 2&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#87d6d5;&quot;&gt;3
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Hacker School: Week 1 Review</title>
		<published>2014-10-11T00:00:00+00:00</published>
		<updated>2014-10-11T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/hacker-school-week-1-review/" type="text/html"/>
		<id>https://zefira.dev/posts/hacker-school-week-1-review/</id>
		<content type="html">&lt;p&gt;So, I can&#x27;t sleep, and it&#x27;s the end of my first week at
&lt;a href=&quot;https:&#x2F;&#x2F;www.hackerschool.com&#x2F;&quot;&gt;Hacker School&lt;&#x2F;a&gt;, so I thought I&#x27;d do some reflecting on what I did,
why I&#x27;m here and similar topics.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;h2 id=&quot;week-review&quot;&gt;&lt;a href=&quot;#week-review&quot; aria-label=&quot;Anchor link for: week-review&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Week Review&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;monday&quot;&gt;&lt;a href=&quot;#monday&quot; aria-label=&quot;Anchor link for: monday&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Monday&lt;&#x2F;h3&gt;
&lt;p&gt;This week has been a blur in some ways and incredibly long in others.
I started out on Monday with an interesting but ultimately abortive
attempt to pair with Alyssa Carter on her observational type system
implementation in Idris. Given that I know pretty much nothing about
either type theory or Idris, this outcome was probably somewhat
inevitable.  In retrospect, while it was interesting to get some
exposure to the ideas and concepts that she talked about, I probably
should have admitted more freely when things she was saying were going
over my head. This is something that I&#x27;ve always struggled with, and I
think that Hacker School is a great place to try and tackle getting
over it.&lt;&#x2F;p&gt;
&lt;p&gt;The rest of Monday I spent flailing. And not really with any code;
mostly with just getting familiarized with Zulip and the HS (physical)
environment, and turning off most notifications in Zulip.  I
discovered an interesting thing about myself that I hadn&#x27;t been fully
aware of previously: when there are constant notifications happening
(like when you&#x27;re highly subscribed to Zulip and desktop notifications
are turned on), I get really stressed out on a subconscious level.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s sort of similar to how I start to feel inexplicably rushed when
my bladder is getting full, but before I actually notice the urge to
pee.&lt;&#x2F;p&gt;
&lt;p&gt;Anyhow, during my flailing I also poked a bit at my
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;snake-puzzle-solver&quot;&gt;snake-puzzle-solver&lt;&#x2F;a&gt; project, and discovered that I&#x27;d left it in a
sort of broken-ish state.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tuesday&quot;&gt;&lt;a href=&quot;#tuesday&quot; aria-label=&quot;Anchor link for: tuesday&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Tuesday&lt;&#x2F;h3&gt;
&lt;p&gt;On Tuesday I felt much calmer. I&#x27;m having a hard time remembering now
what exactly I worked on. I believe it was working through
&lt;em&gt;[Real World OCaml]&lt;&#x2F;em&gt; though.  I didn&#x27;t get very far, but I also spent
a bit of time [helping Sammy out][masterstable], and fixing up this
blog with Octopress.&lt;&#x2F;p&gt;
&lt;p&gt;[masterstable]: {% post_url 2014-10-07-dot-dot-dot-and-this-is-why-master-should-be-stable %}
[Real World OCaml]: https:&#x2F;&#x2F;realworldocaml.org&#x2F;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;wednesday&quot;&gt;&lt;a href=&quot;#wednesday&quot; aria-label=&quot;Anchor link for: wednesday&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Wednesday&lt;&#x2F;h3&gt;
&lt;p&gt;Through some poor decision-making Tuesday evening (i.e. eating two
slices of pizza, and also drinking a not inconsiderable amount) I was
either very gluten-sick or very, very hungover on Wednesday. No good,
very bad feels were had all day. At the time I was fairly convinced
that it was the pizza. In retrospect, the symptoms were very
hangover-like. Perhaps I just got much drunker than I thought I did?
Hard to say.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thursday&quot;&gt;&lt;a href=&quot;#thursday&quot; aria-label=&quot;Anchor link for: thursday&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Thursday&lt;&#x2F;h3&gt;
&lt;p&gt;On Thursday I powered through the first third or so of &lt;em&gt;Real World
OCaml&lt;&#x2F;em&gt;. That was awesome. OCaml is a fascinating language, and even
though it has perhaps more than it&#x27;s share of syntactic quirks it&#x27;s
been fun learning it. On a slightly meta-level I was sort of
dissatisfied throughout the day because of my (mostly self-imposed)
isolation. Not using Zulip much - because of how distracting it is -
makes me feel a bit cut-off from some of the social aspects of HS. And
I still haven&#x27;t really found the courage to seek out somebody to pair
with. Another thing I want to work on. Also, the fact that I was doing
something so ordinary and mundane as simply reading a book made me
feel bad. Reading a book on a new language and working through the
code examples is something that I can, have, and - most likely - will
do again at home. So why am I &amp;quot;wasting&amp;quot; my time at Hacker School,
precious, precious time that it is, doing it here? Particularly since
I&#x27;m doing it alone!!&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t really have answers to most of these dissatisfactions. Most of
them are probably just my social awkwardness manifesting, and the last
one sounds suspiciously like a strange form of Imposter Syndrome.&lt;&#x2F;p&gt;
&lt;p&gt;I stayed late in the evening though and started working on a neat
project that occurred to me when I suggested that another HS&#x27;er work
through Phil Nelson&#x27;s minishell - implementing the minishell in
OCaml!! And even more importantly, I achieved a real-feeling amount of
success in the project! I was able, without any real documentation
(couldn&#x27;t find accurate docs!) to utilize the OCaml Unix module well
enough to create the equivalent of the &lt;code&gt;minishell.c&lt;&#x2F;code&gt; that Nelson gives
out as the basis for the shell, and to complete the equivalent of
assignment 1.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;friday&quot;&gt;&lt;a href=&quot;#friday&quot; aria-label=&quot;Anchor link for: friday&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Friday&lt;&#x2F;h3&gt;
&lt;p&gt;I somehow gained the impression that showing up at the space was less
expected on Friday. Now I&#x27;m really not sure where&#x2F;how I got that
idea.  But I&#x27;m also totally unsure if it&#x27;s actually wrong... &amp;gt;:(&lt;&#x2F;p&gt;
&lt;p&gt;I did however use the day to catch up on some sleep, do some errands
(digital ones anyhow) and go hang out with a friend I haven&#x27;t seen in
literally years. So, overall win even if I did totally miss out on a
HS day.  But again, it makes me feel sort of disconnected to be not at
the space when others are.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;project-ideas&quot;&gt;&lt;a href=&quot;#project-ideas&quot; aria-label=&quot;Anchor link for: project-ideas&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Project Ideas&lt;&#x2F;h2&gt;
&lt;p&gt;Given some of my meta-dissatisfaction that I felt on Thursday
regarding what I&#x27;ve been working on, I thought I might try to list
some other projects that seem more &amp;quot;Hacker School worthy&amp;quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Looking to the &lt;a href=&quot;https:&#x2F;&#x2F;www.hackerschool.com&#x2F;manual#sec-principles&quot;&gt;three traits of an awesome Hacker Schooler&lt;&#x2F;a&gt;,
I started thinking about what are some challenging (strive for
greatness) problems that I could approach with rigor.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Dive into the bug in auto-fill in emacs, try to fix it&lt;&#x2F;li&gt;
&lt;li&gt;Pursue learning more graphics stuff (since I&#x27;ve been sort of
intimidated by it for a while). Project-wise, it might be
interesting to try and discover what sort of work it would take to
update Emacs&#x27; rendering engine.&lt;&#x2F;li&gt;
&lt;li&gt;Try to dive into the Boomerang decompiler&#x27;s source code and
understand it&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And some other random things I want to do (but might not be feasible):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Implement a language that has lispy-prefix syntax but OCaml
semantics; in particular that has type-inferencing&lt;&#x2F;li&gt;
&lt;li&gt;To that end, implement the type inferencing engine that powers OCaml
type inferences&lt;&#x2F;li&gt;
&lt;li&gt;Port Boomerang to use the LLVM architecture&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;&lt;a href=&quot;#final-thoughts&quot; aria-label=&quot;Anchor link for: final-thoughts&quot;&gt;&lt;i class=&quot;fa fa-link&quot; aria-hidden=&quot;true&quot; &gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Final Thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;It&#x27;s frustrating how many of the things that I want to do still have
what seems like huge mounds of prerequisites in front of them. I want
to do all of these interesting language things, but I feel like I&#x27;m
blocked from doing them because I want to do them in LLVM, but I don&#x27;t
know anything about actually using the LLVM.&lt;&#x2F;p&gt;
&lt;p&gt;Also, when I was reflecting on what I need to do to become a better
programmer, one of the recurring thoughts I responded with is that I
need to write&#x2F;work on a larger system&#x2F;project. I feel like I have
quite a bit of experience taking an small projects. But not something
like YRAS... Which, I think, is one reason that I am absolutely
terrified of starting that project.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>...and this is why master should be stable</title>
		<published>2014-10-07T00:00:00+00:00</published>
		<updated>2014-10-07T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/dot-dot-dot-and-this-is-why-master-should-be-stable/" type="text/html"/>
		<id>https://zefira.dev/posts/dot-dot-dot-and-this-is-why-master-should-be-stable/</id>
		<content type="html">&lt;p&gt;Second day at Hacker School.  I spent the morning doing two things:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;getting my blog setup to use &lt;a href=&quot;http:&#x2F;&#x2F;octopress.org&#x2F;&quot;&gt;Octopress&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;helping another HS-er troubleshoot getting setup with &lt;a href=&quot;http:&#x2F;&#x2F;flask.pocoo.org&#x2F;&quot;&gt;Flask&lt;&#x2F;a&gt; and &lt;a href=&quot;http:&#x2F;&#x2F;flask.pocoo.org&#x2F;docs&#x2F;0.10&#x2F;tutorial&#x2F;introduction&#x2F;&quot;&gt;Flaskr&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!--more--&gt;
&lt;p&gt;Yesterday, I was super frustrated by the difficulties I had in getting
Octopress going, and was reminded of the frustrations with setting up
Ruby environments that led me to wipe my computer and start from
scratch a few weeks ago.  You know, that and a certain amount of boredom.&lt;&#x2F;p&gt;
&lt;p&gt;Anyhow, I was able to make more headway today, largely because I
sorted out all of the really silly stuff yesterday.&lt;&#x2F;p&gt;
&lt;p&gt;But helping Sammy with setting up &lt;a href=&quot;http:&#x2F;&#x2F;flask.pocoo.org&#x2F;&quot;&gt;Flask&lt;&#x2F;a&gt; was a nightmare!  TL;DR, we
figured it out, and it was incredibly simple.&lt;&#x2F;p&gt;
&lt;p&gt;First off, there were some minor SNAFU&#x27;s with me showing her about
[virtualenv], and explaining briefly how it works and how why she
should use it.  But then, we were confronted with these instructions
on the [Flaskr doc page][flaskr-github] on Github, a natural place to
look when the &lt;a href=&quot;http:&#x2F;&#x2F;flask.pocoo.org&#x2F;docs&#x2F;0.10&#x2F;tutorial&#x2F;introduction&#x2F;&quot;&gt;&amp;quot;actual&amp;quot; docs&lt;&#x2F;a&gt; don&#x27;t mention anything about how
to install or setup the damn thing.&lt;&#x2F;p&gt;
&lt;p&gt;We spent nearly two and a half hours searching for the mythical
&lt;code&gt;flask&lt;&#x2F;code&gt; binary, to no avail.  Finally, after I inadvertently ran
aacross this [flask issue][issue], it dawned on me that we might be
having the same problem.  Well, that&#x27;s not quite true.  In reality, I
got so frustrated that I decided to just try the simplest thing that I
could think of to get flaskr to run &lt;code&gt;python flaskr.py&lt;&#x2F;code&gt;.  Low and
behold, it worked!!  Then, in retrospect, having seen that issue
describing the disconnect between the docs for flaskr in the flask
&lt;code&gt;master&lt;&#x2F;code&gt; branch and what the latest stable version was, I went and
looked at the [last stable release docs][laststable] for Flaskr, and
there it was. Simple instructions to do the simple, straightforward
thing.&lt;&#x2F;p&gt;
&lt;p&gt;[[virtualenv]: http:&#x2F;&#x2F;virtualenv.readthedocs.org&#x2F;en&#x2F;latest&#x2F;virtualenv.html
[flaskr-github]: https:&#x2F;&#x2F;github.com&#x2F;mitsuhiko&#x2F;flask&#x2F;tree&#x2F;master&#x2F;examples&#x2F;flaskr
[issue]: https:&#x2F;&#x2F;github.com&#x2F;mitsuhiko&#x2F;flask&#x2F;issues&#x2F;1180
[laststable]: https:&#x2F;&#x2F;github.com&#x2F;mitsuhiko&#x2F;flask&#x2F;tree&#x2F;0.10.1&#x2F;examples&#x2F;flaskr&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>LeJOS and Clojure</title>
		<published>2014-04-17T00:00:00+00:00</published>
		<updated>2014-04-17T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/lejos-and-clojure/" type="text/html"/>
		<id>https://zefira.dev/posts/lejos-and-clojure/</id>
		<content type="html">&lt;p&gt;This is a short followup to my first post about
[experimenting with the Lego EV3&#x27;s][lego-ev3] and &lt;a href=&quot;http:&#x2F;&#x2F;lejos.org&quot;&gt;leJOS&lt;&#x2F;a&gt;. Shortly
after I wrote that post, I went on the Clojure IRC channel and talked
to &lt;a href=&quot;http:&#x2F;&#x2F;technomancy.us&#x2F;&quot;&gt;Phil Hagelberg&lt;&#x2F;a&gt; and some other helpful folks about my
issues. They steered me away from attempting to install &lt;a href=&quot;http:&#x2F;&#x2F;leiningen.org&#x2F;&quot;&gt;Leiningen&lt;&#x2F;a&gt; on
the EV3 itself, which was a relief since I think that way lay
madness. Instead, they suggested that I have a small launcher program
that would just setup a REPL. Then I could run my robot-controlling
Clojure code from there.&lt;&#x2F;p&gt;
&lt;p&gt;[lego-ev3]: {% post_url 2013-10-31-leJOS-and-EV3 %}&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;This advice led to the creation of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RadicalZephyr&#x2F;ev3-nrepl&quot;&gt;ev3-nrepl&lt;&#x2F;a&gt;. It&#x27;s basically a small
skeleton Clojure project to provide the basis for running Clojure code
on the EV3. It&#x27;s a minimalist setup, so it should provide a good
starting point for other people to continue experimenting. I tried to
explain how to use it fairly clearly, as well as add all the links to
the necessary documentation to get leJOS running on the EV3.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, despite this seemingly great start, I never ended up
actually doing anything interesting with Clojure on the EV3. There are
two related reasons for this. First, the robotics class I was in
started having actual coding assignments (thanks to the fact that we
could now run leJOS). Second, it turns out that leJOS is designed from
an incredibly stateful and imperative point of view. This makes it
very hard to develop clean Clojure code that makes use of their
API. Specifically, leJOS makes the assumption that any code making use
of it is going to start-up, do robot stuff, and then die. A Clojure
REPL obviously breaks this assumption rather badly. As it turned out,
this was the most painful when I was trying to figure out how to
program and build my robot at the same time.&lt;&#x2F;p&gt;
&lt;p&gt;What I wanted to do was be able to open a Clojure REPL connect to it,
and then leave it running for a long time. This is my normal modus
operandi, but the EV3 makes it even more critical that this
work. Because of the limited hardware, it takes several minutes for
nrepl to actually boot up.&lt;&#x2F;p&gt;
&lt;p&gt;I think that using Clojure as a prototyping tool for building robots
with the EV3 could be incredibly powerful. All of the
&lt;a href=&quot;http:&#x2F;&#x2F;www.infoq.com&#x2F;presentations&#x2F;Clojure-Java-Interop&quot;&gt;arguments&lt;&#x2F;a&gt;
for why Clojure is a great language for exploring Java API&#x27;s are
applicable to working with the EV3 API&#x27;s. Possibly even more so, since
there is something really, really cool about typing some commands at
the REPL and having your robot start moving around and doing
stuff. Unfortunately, because of the current architecture of leJOS and
the limited processing power of the EV3&#x27;s it&#x27;s not quite there yet.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Clojure, LeJOS and EV3</title>
		<published>2013-10-31T00:00:00+00:00</published>
		<updated>2013-10-31T00:00:00+00:00</updated>
		<link rel="alternate" href="https://zefira.dev/posts/lejos-and-ev3/" type="text/html"/>
		<id>https://zefira.dev/posts/lejos-and-ev3/</id>
		<content type="html">&lt;p&gt;I&#x27;ve had the opportunity in the last couple weeks to start playing
with a Lego Mindstorms EV3.  Since this hardware is such a new release
though, most of the normal contenders in the robot programming scene
(namely, RobotC) haven&#x27;t had time to update their offerings to work
with it.&lt;&#x2F;p&gt;
&lt;p&gt;Enter &lt;a href=&quot;http:&#x2F;&#x2F;lejos.org&quot;&gt;LeJOS&lt;&#x2F;a&gt;.  Apparently the maintainer of the LeJOS project
got early access to the developer documentation and other necessary
infos, so he&#x27;s been able to develop a setup for allowing people to
program their EV3 using Java.&lt;&#x2F;p&gt;
&lt;!--more--&gt;
&lt;p&gt;It&#x27;s a really elegant solution actually.  Since the EV3 already runs a
full linux kernel, he just modified the base Legos linux image.  You
then partition a microSD card and write this image to it.  Now you can
boot the EV3 from the microSD card and ssh into it over either WiFi
(if you have an external USB wifi adapter that&#x27;s compatible), or over
USB (a more recent feature).&lt;&#x2F;p&gt;
&lt;p&gt;My next goal is to get a clojure projet running on the ev3.  There are
two approaches that I could take.  First, I could try AOT compiling my
clojure source and then shipping just the uberjar to the EV3.  This
seems the most straightforward.  However, following this plan I almost
immediately ran into a stumbling block.  The LeJOS java library cannot
be compiled using Leiningen when not on the EV3.&lt;&#x2F;p&gt;
&lt;p&gt;Apparently this is because something about the clojure compilation
process actually loads the EV3 classes into the JVM.  This causes the
static initializers to be run.  And the static initializers look for
specific files in the &#x2F;dev directory to try and do their thing.&lt;&#x2F;p&gt;
&lt;p&gt;Obviously, when you&#x27;re not on an EV3 these files don&#x27;t exist.&lt;&#x2F;p&gt;
&lt;p&gt;So the second way of doing things would be to attempt to install
leiningen on the EV3 itself.  I see a lot of potential problems with
this, first and foremost being how do I do it without a direct
connection to the internet?  Secondly, the linux installation is very
minimal, and might not actually contain all the necessary tools to
install and use leiningen.&lt;&#x2F;p&gt;
</content>
	</entry>
</feed>
