<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
  <id>http://www.flyingmachinestudios.com/</id>
  <title>Flying Machine Studios</title>
  <updated>2013-04-07T14:23:00Z</updated>
  <link rel="alternate" href="http://www.flyingmachinestudios.com/" />
  
  <author>
    <name>Daniel Higginbotham</name>
    <uri>http://www.flyingmachinestudios.com</uri>
  </author>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/FlyingMachineStudios" /><feedburner:info uri="flyingmachinestudios" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:browserFriendly></feedburner:browserFriendly><entry>
    <id>tag:www.flyingmachinestudios.com,2013-04-07:/programming/how-clojure-babies-are-made-what-leiningen-is/</id>
    <title type="html">How Clojure Babies are Made: What Leiningen Is</title>
    <published>2013-04-07T14:23:00Z</published>
    <updated>2013-04-07T14:23:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/programming/how-clojure-babies-are-made-what-leiningen-is/" />
    <content type="html">&lt;p&gt;&amp;quot;What the hell is Leiningen?&amp;quot; is a question you&amp;#39;ve probably overheard
many times in your day-to-day life. You&amp;#39;ve probably even asked it
yourself. Up until now we&amp;#39;ve described specific capabilities that
Leiningen has and how those capabilities are implemented. It can
&lt;a href="/programming/how-clojure-babies-are-made-lein-run"&gt;build and run your app&lt;/a&gt;,
it &lt;a href="/programming/lein-run"&gt;has a trampoline&lt;/a&gt;, and so forth.&lt;/p&gt;

&lt;p&gt;But it&amp;#39;s time to take a step back and get a high-level understanding
of what Leiningen is. It&amp;#39;s time to stare deeply into Leiningen&amp;#39;s eyes
and say &amp;quot;I see you,&amp;quot; like Jake Sully in that Avatar documentary. We&amp;#39;ll
do this by giving an overview of the non-coding related tasks you need
to accomplish when building software. Next, we&amp;#39;ll describe how
Leiningen helps you accomplish these tasks and compare it to similar
tools in Ruby.&lt;/p&gt;

&lt;p&gt;This post isn&amp;#39;t as nitty-gritty as the previous posts in the Clojure
Babies series, but it will help lay the groundwork for an upcoming
post on packaging. Additionally, I hope it will clarify what a
programming language artifact ecosystem is. This concept is often
overlooked when teaching a programming language, and when it &lt;em&gt;is&lt;/em&gt;
covered it&amp;#39;s not covered in a systematic way. Together, noble-chinned
reader, we will remedy that situation. For our generation and all
generations to come.&lt;/p&gt;

&lt;h2&gt;Programming Language Artifact Ecosystems&lt;/h2&gt;

&lt;p&gt;In order to become proficient at a language, you need to know much
more than just its syntax and semantics. You need to familiarize
yourself with the entire programming language ecosystem, which is
comprised of everything you need in order to build working software in
that language. It can be broken down into at least the following
sub-ecosystems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The documentation ecosystem&lt;/li&gt;
&lt;li&gt;The developer community&lt;/li&gt;
&lt;li&gt;The development environment ecosystem (editor support)&lt;/li&gt;
&lt;li&gt;The artifact ecosystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Right now we only care about the artifact ecosystem. For our purposes,
a programming artifact is a library or executable. Ruby gems, shell
scripts, Java jars, shared libraries, and &amp;quot;HAL9000.exe&amp;quot; are all
programming artifacts.&lt;/p&gt;

&lt;p&gt;An artifact ecosystem is the set of tools and services that allow
you to do the following with regard to artifacts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieve them from repositories&lt;/li&gt;
&lt;li&gt;Incorporate them in your own project, (possibly) resolving conflicts&lt;/li&gt;
&lt;li&gt;Build them&lt;/li&gt;
&lt;li&gt;Publish them to repositories&lt;/li&gt;
&lt;li&gt;Run them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools are often layered on top of each other, one tool smoothing out
the warts of the tools it wraps. For example, the following tools (and
more) are part of the Ruby artifact ecosystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Ruby Gems&lt;/em&gt; provides a package specification, the means to
incorporate gems in your project, and the means to build and publish
gems&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="http://rubygems.org"&gt;rubygems.org&lt;/a&gt;&lt;/em&gt; is a central repo for gems&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Bundler&lt;/em&gt; provides a layer on top of Ruby Gems, providing dependency
resolution and gem retrieval&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Jeweler&lt;/em&gt; is one of many tools for easing the process of creating
gemspecs and building gems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other languages have their own tools. Java has Maven, PHP has Pear or
whatever. Artifact management is a common need across languages.&lt;/p&gt;

&lt;p&gt;In previous Clojure Baby posts, we&amp;#39;ve seen that we can use Leiningen
to build and run Clojure programs. It turns out that Leiningen also
handles the remaining tasks - retrieving packages, incorporating them
in your project, and publishing them. It&amp;#39;s truly the Swiss Army
Bazooka (I&amp;#39;m going to keep repeating that phrase until it catches on)
of the Clojure artifact ecosystem.&lt;/p&gt;

&lt;p&gt;But why is it that in Ruby you need an entire constellation of tools,
while in Clojure you only need one?&lt;/p&gt;

&lt;h2&gt;Leiningen Is a Task Runner with Clojure Tasks Built In&lt;/h2&gt;

&lt;p&gt;Leiningen is able to handle so many responsibilities because it is, at
heart, a task runner. It just happens to come with an
&lt;a href="https://github.com/technomancy/leiningen/tree/master/src/leiningen"&gt;excellent set of built-in tasks&lt;/a&gt;
for handling Clojure artifacts. (Incidentally, this is probably where
Leiningen&amp;#39;s name came from. &amp;quot;Leiningen Versus the Ants&amp;quot; is a short
story where the protagonist fights ants. Ant is a Java build tool that
evidently is unpleasant to use for Clojure builds.) By comparison,
Ruby&amp;#39;s Rake is also a task runner used by many of Ruby&amp;#39;s artifact
tools, but Rake provides no built-in tasks for working with Ruby
artifacts.&lt;/p&gt;

&lt;p&gt;&amp;quot;Task runner&amp;quot; is a little bit ambiguous, so let&amp;#39;s break it down.
Ultimately, all Leiningen tasks are just Clojure functions. However,
in &lt;a href="/programming/how-clojure-babies-are-made-lein-run"&gt;previous posts&lt;/a&gt;
we&amp;#39;ve seen how fun it is to try and run Clojure functions from the
command line. In case you need a short refresher: it&amp;#39;s not fun at all!&lt;/p&gt;

&lt;p&gt;Leiningen allows the Clojure party to remain fun by serving as an
adapter between the CLI and Clojure. It takes care of the plumbing
required for you to run a Clojure function. Whether the function is
provided by your project, by Leiningen&amp;#39;s built-in tasks, or by a
&lt;a href="https://github.com/technomancy/leiningen/blob/master/doc/PLUGINS.md"&gt;Leiningen plugin&lt;/a&gt;,
Leiningen does everything necessary to get the function to run. In a
way, Leiningen&amp;#39;s like an attentive butler who quietly and competently
takes care of all your chores so that you can focus on your true
passions, like knitting sweaters for gerbils or whatever.&lt;/p&gt;

&lt;p&gt;This manner of executing code was foreign to me when I first came to
Clojure. At that time I had mostly coded in Ruby and JavaScript, and I
had a decent amount of experience in Objective C. Those languages
represent two different paradigms of code execution.&lt;/p&gt;

&lt;p&gt;Ruby and Javascript, being scripting languages, don&amp;#39;t require
compilation and execute statements as they&amp;#39;re encountered. Objective C
requires compilation and always starts by executing a &lt;code&gt;main&lt;/code&gt; method.
With Leiningen, Clojure has achieved an amalgamation of the two
paradigms by allowing you to easily run arbitrary functions with a
compiled language.&lt;/p&gt;

&lt;h2&gt;The End&lt;/h2&gt;

&lt;p&gt;Hopefully, this article has given you a firmer grasp of what Leiningen
is. The idea that Leiningen is a task runner with a powerful set of
built-in tasks designed to aid Clojure artifact management should help
you organize your disparate chunks of Leiningen knowledge.&lt;/p&gt;

&lt;p&gt;In the next article, we&amp;#39;ll add another chunk of Leiningen khnowledge
by examining the way Leiningen retrieves artifacts from repositories
and incorporates them in your project.&lt;/p&gt;

&lt;p&gt;Goodbye for now!&lt;/p&gt;

&lt;h2&gt;Shout Outs&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;a href="http://patshaughnessy.net/"&gt;Pat Shaughnessy&lt;/a&gt; and
&lt;a href="http://technomancy.us/"&gt;technomancy&lt;/a&gt; for reviewing this article.
technomancy provided the line &amp;quot;Leiningen is an adapter between the CLI
and Clojure&amp;quot;, which really helped!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2013-03-23:/programming/lein-trampoline/</id>
    <title type="html">How Clojure Babies are Made: Leiningen's Trampoline</title>
    <published>2013-03-23T14:23:00Z</published>
    <updated>2013-03-23T14:23:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/programming/lein-trampoline/" />
    <content type="html">&lt;p&gt;In
&lt;a href="/programming/how-clojure-babies-are-made-lein-run/"&gt;the last &amp;quot;How Clojure Babies are Made&amp;quot; article&lt;/a&gt;
I hinted that Leiningen avoids waste by using a trampoline. In this
installment of this awkwardly-named Clojure series, you&amp;#39;ll learn what
the trampoline does and how it does it.&lt;/p&gt;

&lt;h2&gt;The Rationale Behind the Trampoline&lt;/h2&gt;

&lt;p&gt;I know what you&amp;#39;re thinking, wise-hearted reader. &amp;quot;Why would anyone
need to provide a rationale for a trampoline? That&amp;#39;s like trying to
give a reason for rainbows, or a newborn&amp;#39;s laughter, or Michael
Jackson&amp;#39;s &lt;em&gt;Thriller&lt;/em&gt;.&amp;quot;&lt;/p&gt;

&lt;p&gt;Allow me to explain myself. &lt;code&gt;lein trampoline&lt;/code&gt; does indeed give you a
feeling of weightless freedom, just not in the way that you&amp;#39;re used
to.&lt;/p&gt;

&lt;p&gt;See, whenever you use Leiningen to run code from your project, you end
up with two Java processes running. Each process loads a separate
instance of the
&lt;a href="http://en.wikipedia.org/wiki/Java_virtual_machine"&gt;JVM&lt;/a&gt;. We saw this
in
&lt;a href="/programming/how-clojure-babies-are-made-lein-run/"&gt;the previous article&lt;/a&gt;
in the output of &lt;code&gt;ps | grep lein&lt;/code&gt;. The first process is for Leiningen
itself, and it&amp;#39;s responsible for setting up everything necessary for
your project code to run. The second process is where your code
actually executes. If you were to run &lt;code&gt;lein -h&lt;/code&gt;, you would only start
one Java process, as none of your project code would need to be
executed.&lt;/p&gt;

&lt;p&gt;Leiningen starts a separate process for your project in order to
enforce isolation. This is because Leiningen is a true gentleman who
does not allow his namespaces and dependencies (like, say, a
completely different version of Clojure) to interfere with your
meticulously hand-crafted, artisinal program.&lt;/p&gt;

&lt;p&gt;However, like a doting father, the Leiningen process continues to stay
open for the entire duration of your program&amp;#39;s execution. If you have
a long-running process, like a web server for your Justin Bieber fan
site, then Leiningen stays open the whole time consuming memory that
could be put to use in compositing images of the Biebs with hearts all
over them.&lt;/p&gt;

&lt;p&gt;This is where the trampoline comes into play. It allows the Leiningen
process to exit completely before your project&amp;#39;s process starts. Now,
instead of two JVM&amp;#39;s running, you only have one.&lt;/p&gt;

&lt;p&gt;I think the name &amp;quot;trampoline&amp;quot; was chosen to evoke an image of
Leiningen providing a launching point for your program. However, I
choose to envision the trampoline process as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Leiningen takes your program, which is embodied as one of those
cymbal-clanging monkeys with unsettling eyes, and winds it up.&lt;/li&gt;
&lt;li&gt;Leiningen gingerly places the wind-up monkey which is your program
on the floor of a cozy Hobbit hole.&lt;/li&gt;
&lt;li&gt;Leiningen steps outside and mounts a gigantic trampoline in Bilbo&amp;#39;s
front yard.&lt;/li&gt;
&lt;li&gt;Leiningen takes two warm-up bounces and then, with a mighty
&amp;quot;Hyup!&amp;quot;, rockets himself into the sky, his mustaches flapping in
the wind. He grows smaller and smaller until, with a bright
sparkle, he disappears entirely.&lt;/li&gt;
&lt;li&gt;Your cymbal-clanging web server starts up, allowing users to
profess their undying love for teenage pop stars.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;How lein trampoline Works&lt;/h2&gt;

&lt;p&gt;Though you don&amp;#39;t really need to understand how &lt;code&gt;lein trampoline&lt;/code&gt; works
in order to use it, I think it&amp;#39;s pretty cool. Below I walk you through
it step by step, with relevant code. We&amp;#39;ll be using the project under
&lt;code&gt;leiningen/lein-build&lt;/code&gt; of the
&lt;a href="https://github.com/flyingmachine/make-a-clojure-baby/tree/master/leiningen/lein-build"&gt;make-a-clojure-baby github repo&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;lein trampoline run&lt;/code&gt; from the command line. If you&amp;#39;re on a linux machine,
this executes a
&lt;a href="https://github.com/technomancy/leiningen/blob/6a70dc32362406be17189adc3c3a8d49e6594810/bin/lein"&gt;bash script&lt;/a&gt;.
This script is probably at ~/bin/lein on your system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The bash script
&lt;a href="https://github.com/technomancy/leiningen/blob/6a70dc32362406be17189adc3c3a8d49e6594810/bin/lein#L273"&gt;sets the &lt;code&gt;TRAMPOLINE_FILE&lt;/code&gt;&lt;/a&gt;
environment variable to a path. Later in this process, Leiningen
will write a command to this file. Here&amp;#39;s the part of the script
that sets the environment variable:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;([&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$LEIN_FAST_TRAMPOLINE&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -r .lein-fast-trampoline &lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt; -r project.clj &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;INPUTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$@ $(cat project.clj) $LEIN_VERSION $(cat &amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$LEIN_HOME&lt;/span&gt;/profiles.clj&lt;span class="s2"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
    &lt;span class="nv"&gt;INPUT_CHECKSUM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$INPUTS&lt;/span&gt; | shasum - | cut -f 1 -d &lt;span class="s2"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;# Just don&amp;#39;t change :target-path in project.clj, mkay?&lt;/span&gt;
    &lt;span class="nv"&gt;TRAMPOLINE_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;target/trampolines/$INPUT_CHECKSUM&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;TRAMPOLINE_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/tmp/lein-trampoline-$$&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;trap&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;rm -f $TRAMPOLINE_FILE&amp;quot;&lt;/span&gt; EXIT
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The first Java process starts:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;TieredCompilation&lt;/span&gt;  &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Xbootclasspath&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;installs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;2&lt;span class="p"&gt;.&lt;/span&gt;0&lt;span class="p"&gt;.&lt;/span&gt;0&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;UTF&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;8 &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dmaven&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wagon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;easy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dleiningen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;web_sites&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dleiningen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;installs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;2&lt;span class="p"&gt;.&lt;/span&gt;0&lt;span class="p"&gt;.&lt;/span&gt;0&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt; `# &lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;` &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="n"&gt;trampoline&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; 1
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This causes Java to execute the &lt;code&gt;-main&lt;/code&gt; method in &lt;code&gt;clojure.main&lt;/code&gt;,
which in turn loads &lt;code&gt;leiningen.core.main&lt;/code&gt; and executes its &lt;code&gt;-main&lt;/code&gt;
function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;leiningen.core.main/-main&lt;/code&gt; applies the
&lt;a href="https://github.com/technomancy/leiningen/blob/6a70dc32362406be17189adc3c3a8d49e6594810/src/leiningen/trampoline.clj#L44"&gt;trampoline task&lt;/a&gt;:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="ss"&gt;:higher-order&lt;/span&gt; &lt;span class="nv"&gt;trampoline&lt;/span&gt;
  &lt;span class="s"&gt;&amp;quot;Run a task without nesting the project&amp;#39;s JVM inside Leiningen&amp;#39;s.&lt;/span&gt;

&lt;span class="s"&gt;Calculates the Clojure code to run in the project&amp;#39;s process for the&lt;/span&gt;
&lt;span class="s"&gt;given task and allows Leiningen&amp;#39;s own JVM process to exit before&lt;/span&gt;
&lt;span class="s"&gt;running it rather than launching a subprocess of Leiningen&amp;#39;s JVM.&lt;/span&gt;

&lt;span class="s"&gt;Use this to save memory or to work around stdin issues.&amp;quot;&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;project &lt;/span&gt;&lt;span class="nv"&gt;task-name&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;= &lt;/span&gt;&lt;span class="ss"&gt;:leiningen&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:eval-in&lt;/span&gt; &lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main/info&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Warning: trampoline has no effect with :eval-in-leiningen.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;binding &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;*trampoline?*&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main/apply-task&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main/lookup-alias&lt;/span&gt; &lt;span class="nv"&gt;task-name&lt;/span&gt; &lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;assoc project &lt;/span&gt;&lt;span class="ss"&gt;:eval-in&lt;/span&gt; &lt;span class="ss"&gt;:trampoline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;vary-meta&lt;/span&gt; &lt;span class="nv"&gt;update-in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:without-profiles&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nv"&gt;assoc&lt;/span&gt;
                                    &lt;span class="ss"&gt;:eval-in&lt;/span&gt; &lt;span class="ss"&gt;:trampoline&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                     &lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;eval/trampoline-forms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;write-trampoline&lt;/span&gt; &lt;span class="nb"&gt;project &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;eval/trampoline-forms&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;eval/trampoline-profiles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main/abort&lt;/span&gt; &lt;span class="nv"&gt;task-name&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;did not run any project code for trampolining.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;trampoline&lt;/code&gt; calls &lt;code&gt;leiningen.core.main/apply-task&lt;/code&gt; but with a
twist: it passes that function an updated project configuration,
setting &lt;code&gt;:eval-in&lt;/code&gt; to &lt;code&gt;:trampoline&lt;/code&gt;. You can see this is the
snippet above.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Eventually, &lt;code&gt;leiningen.core.eval/eval-in-project&lt;/code&gt; gets applied. The
cool thing about this function is that it then calls
&lt;code&gt;leiningen.core.eval/eval-in&lt;/code&gt;, which is a multi-method. It has
different definitions for &lt;code&gt;:subprocess&lt;/code&gt;, &lt;code&gt;:trampoline&lt;/code&gt;, &lt;code&gt;:nrepl&lt;/code&gt;,
and a few more. This is one of the first times I&amp;#39;ve seen
&lt;code&gt;defmethod&lt;/code&gt; &amp;quot;in the wild&amp;quot; and it really tickled my pfeffernuesse.
Definitely
&lt;a href="https://github.com/technomancy/leiningen/blob/6a70dc32362406be17189adc3c3a8d49e6594810/leiningen-core/src/leiningen/core/eval.clj#L203"&gt;check it out on github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since we updated our project configuration in the last step so that
&lt;code&gt;:eval-in&lt;/code&gt; is &lt;code&gt;:trampoline&lt;/code&gt;, the &lt;code&gt;:trampoline&lt;/code&gt; method gets matched:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defmethod &lt;/span&gt;&lt;span class="nv"&gt;eval-in&lt;/span&gt; &lt;span class="ss"&gt;:trampoline&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;project &lt;/span&gt;&lt;span class="nv"&gt;form&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;swap!&lt;/span&gt; &lt;span class="nv"&gt;trampoline-forms&lt;/span&gt; &lt;span class="nb"&gt;conj &lt;/span&gt;&lt;span class="nv"&gt;form&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;swap!&lt;/span&gt; &lt;span class="nv"&gt;trampoline-profiles&lt;/span&gt; &lt;span class="nb"&gt;conj &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;select-keys &lt;/span&gt;&lt;span class="nv"&gt;project&lt;/span&gt;
                                               &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dependencies&lt;/span&gt; &lt;span class="ss"&gt;:source-paths&lt;/span&gt;
                                                &lt;span class="ss"&gt;:resource-paths&lt;/span&gt; &lt;span class="ss"&gt;:test-paths&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This updates the &lt;code&gt;trampoline-forms&lt;/code&gt; and &lt;code&gt;trampoline-profiles&lt;/code&gt; atoms
within the &lt;code&gt;leiningen.core.eval&lt;/code&gt; namespace.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;trampoline&lt;/code&gt; function shown in step 5 above continues
executing:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;eval/trampoline-forms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;write-trampoline&lt;/span&gt; &lt;span class="nb"&gt;project &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;eval/trampoline-forms&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;eval/trampoline-profiles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main/abort&lt;/span&gt; &lt;span class="nv"&gt;task-name&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;did not run any project code for trampolining.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;write-trampoline&lt;/code&gt; writes out the entire Java command necessary to
finally run our project&amp;#39;s &lt;code&gt;main&lt;/code&gt; function. It writes this command
to the path in the &lt;code&gt;TRAMPOLINE_FILE&lt;/code&gt; environment variable set by
the bash script in step 2 above.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Leiningen process exits and the bash process from step 2
continues. It checks for the existence of &lt;code&gt;TRAMPOLINE_FILE&lt;/code&gt;, and
since it exists, it essentially evaluates the command in it,
kicking off the Java process which will run your code:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -r &lt;span class="s2"&gt;&amp;quot;$TRAMPOLINE_FILE&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$LEIN_TRAMPOLINE_WARMUP&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;TRAMPOLINE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$(cat $TRAMPOLINE_FILE)&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$INPUT_CHECKSUM&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;        &lt;/span&gt;rm &lt;span class="nv"&gt;$TRAMPOLINE_FILE&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;exec &lt;/span&gt;sh -c &lt;span class="s2"&gt;&amp;quot;exec $TRAMPOLINE&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="nv"&gt;$EXIT_CODE&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It&amp;#39;s a bit of circuitous route, but Leiningen is not one to shy away
from hard work!&lt;/p&gt;

&lt;h2&gt;The End&lt;/h2&gt;

&lt;p&gt;I hope you found this article interesting! The following topics are
next on my list of things to write about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How Leiningen manages dependencies&lt;/li&gt;
&lt;li&gt;How to distribute a full application&lt;/li&gt;
&lt;li&gt;How to distribute a library&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So long for now, and may the lambda be with you!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2013-03-18:/programming/how-clojure-babies-are-made-lein-run/</id>
    <title type="html">How Clojure Babies Are Made: Understanding lein run</title>
    <published>2013-03-18T14:23:00Z</published>
    <updated>2013-03-18T14:23:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/programming/how-clojure-babies-are-made-lein-run/" />
    <content type="html">&lt;p&gt;Leiningen reminds me a lot of Major Alex Louis Armstrong from
Fullmetal Alchemist:&lt;/p&gt;

&lt;p&gt;&lt;img src="/assets/images/posts/leiningen/so-sparkly.png" alt="What artistry!"&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They are both manly&lt;/li&gt;
&lt;li&gt;They are both artistic&lt;/li&gt;
&lt;li&gt;Sometimes you don&amp;#39;t know what the f* they&amp;#39;re saying (but it&amp;#39;s
amazing anyway)&lt;/li&gt;
&lt;li&gt;Mustaches&lt;/li&gt;
&lt;li&gt;Sparkles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Though the Strong Arm Alchemist will forever remain inscrutable, we do
have some hope in understanding Leiningen better. In this post, we&amp;#39;ll
peek under Leiningen&amp;#39;s lederhosen so that we can begin to learn
precisely what it does and how to make effective use of it in
developing, testing, running, and deploying Clojure applications.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s what we&amp;#39;ll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to build and run a Clojure program without Leiningen&lt;/li&gt;
&lt;li&gt;What happens when you run &lt;code&gt;lein run&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Basic Leiningen architecture&lt;/li&gt;
&lt;li&gt;What happens when you run a Leiningen task&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next post, we&amp;#39;ll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How Leiningen avoids waste with a trampoline&lt;/li&gt;
&lt;li&gt;How Leiningen manages dependencies&lt;/li&gt;
&lt;li&gt;How to distribute a full application&lt;/li&gt;
&lt;li&gt;How to distribute a library&lt;/li&gt;
&lt;li&gt;Other stuff Leiningen does&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post builds on
&lt;a href="/programming/how-clojure-babies-are-made-the-java-cycle/"&gt;How Clojure Babies Are Made: Compiling and Running a Java Program&lt;/a&gt;,
so make sure you understand everything in that post first. It doesn&amp;#39;t
have any pictures of sparkly, sensitive, muscle-bound men though so if
that&amp;#39;s what you&amp;#39;re hoping for you&amp;#39;re out of luck. We&amp;#39;re here to learn
Clojure, dammit, not ogle cartoons!&lt;/p&gt;

&lt;h2&gt;Brief Overview of Leiningen&lt;/h2&gt;

&lt;p&gt;Leiningen is the Swiss Army Bazooka of Clojure development. It
handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Project compilation.&lt;/strong&gt; Your Clojure has to get converted into Java
bytecode somehow, and Leiningen automates the process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency management.&lt;/strong&gt; Similar to Ruby&amp;#39;s bundler and gemfiles,
Leiningen automates the process of resolving and downloading the
Java jars your project depends on&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Running tasks.&lt;/strong&gt; Superficially similar to Ruby&amp;#39;s Rake, except that
Rake is not very declarative. This could have its own blog post.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deployment.&lt;/strong&gt; Helps with creating Java jars which can be executed
and/or incorporated in other projects. Similar to Ruby gems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;How to Build and Run a Clojure Program Without Leiningen&lt;/h2&gt;

&lt;p&gt;By understanding how to build and run a Clojure program manually,
you&amp;#39;ll better understand what Leiningen does to automate the process.
We&amp;#39;ll be working with the files under &lt;code&gt;leiningen/manual-build&lt;/code&gt; which
you can get from the
&lt;a href="https://github.com/flyingmachine/make-a-clojure-baby"&gt;make a clojure baby repo&lt;/a&gt;.
All path references will be relative to &lt;code&gt;make-a-clojure-baby/leiningen/manual-build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The program we&amp;#39;re compiling will make us fluent in the ways of German
Love:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;ns &lt;/span&gt;&lt;span class="nv"&gt;learn-a-language.important-phrases&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:gen-class&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;;; It&amp;#39;s time for some German love! &lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;german&lt;/span&gt;
  &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;I love you.&amp;quot;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Ich liebe dich.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;You make me so happy!&amp;quot;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Du machst mich so glucklich!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;I miss you.&amp;quot;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Ich vermisse dich./Du fehlst mir.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Pass me the mustard.&amp;quot;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Gib mir den Senf.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   
   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Kiss me!&amp;quot;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Kuss mich!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;-main&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;which&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;phrases&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get &lt;/span&gt;&lt;span class="nv"&gt;german&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Integer.&lt;/span&gt; &lt;span class="nv"&gt;which&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;English: &amp;quot;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;phrases&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;German: &amp;quot;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;second &lt;/span&gt;&lt;span class="nv"&gt;phrases&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;One important thing to note here is that we included the &lt;code&gt;:gen-class&lt;/code&gt;
directive in the &lt;code&gt;ns&lt;/code&gt; declaration. This tells Clojure to generate a
named Java class when it compiles the namespace. Remember that Java
requires a &lt;code&gt;public main&lt;/code&gt; method within a &lt;code&gt;public&lt;/code&gt; class to serve as
the entry point for the JVM. Using &lt;code&gt;:gen-class&lt;/code&gt; allows us to use
&lt;code&gt;learn-a-language.important-phrases/-main&lt;/code&gt; as the entry point.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s go ahead and compile. First, start up a Clojure repl (note that
the git repo includes the 1.5.1 release of Clojure as clojure.jar):&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="p"&gt;.:&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Notice that we specifed the classpath with &lt;code&gt;-cp .:clojure.jar&lt;/code&gt;. This
does two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It allows us to execute the &lt;code&gt;main&lt;/code&gt; method in &lt;code&gt;clojure.main&lt;/code&gt;
similarly to what we saw at the end of
&lt;a href="/programming/how-clojure-babies-are-made-the-java-cycle/"&gt;the last post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;It adds the current directory to the classpath so that when you
actually start loading Clojure files and compiling namespaces, the
Clojure repl can find them. To see what I mean, try starting the
repl with &lt;code&gt;java -jar clojure.jar&lt;/code&gt; and then running the code below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should now have a Clojure repl running in your terminal. Copy and
paste the following lines into it:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;load &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;learn_a_language/important_phrases&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt; &lt;span class="ss"&gt;&amp;#39;learn-a-language.important-phrases&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The first line reads the specified file. The second actually compiles
the &lt;code&gt;learn-a-language.important-phrases&lt;/code&gt; namespace, generating a
boatload of Java class files in the &lt;code&gt;classes/learn_a_language&lt;/code&gt;
directory:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;$ &lt;span class="n"&gt;ls&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;learn_a_language&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="n"&gt;important_phrases&lt;/span&gt;$&lt;span class="n"&gt;_main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;span class="n"&gt;important_phrases&lt;/span&gt;$&lt;span class="n"&gt;fn__19&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;span class="n"&gt;important_phrases&lt;/span&gt;$&lt;span class="n"&gt;fn__48&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;span class="n"&gt;important_phrases&lt;/span&gt;$&lt;span class="n"&gt;loading__4910__auto__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;span class="n"&gt;important_phrases&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;span class="n"&gt;important_phrases__init&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;(I won&amp;#39;t go into into detail about the purposes of the various class files,
but you can start to learn more about that in
&lt;a href="http://clojure.org/compilation"&gt;clojure&amp;#39;s compilation documentation&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;After going through the above steps, you might have a question on your
mind grapes: &amp;quot;Where did the &lt;code&gt;classes&lt;/code&gt; directory come from?&amp;quot;&lt;/p&gt;

&lt;p&gt;Oh, gentle-hearted reader. Your dedication to learning has touched my
heart. I shall answer your query: Clojure places compiled files under
&lt;code&gt;*compile-path*&lt;/code&gt;, which is &lt;code&gt;classes&lt;/code&gt; by default. Therefore, &lt;code&gt;classes&lt;/code&gt;
must exist and be accessible from the classpath. You&amp;#39;ll notice that
there&amp;#39;s a &lt;code&gt;classes&lt;/code&gt; directory in the git repo with a &lt;code&gt;.gitkeep&lt;/code&gt; file
in it. Never change, dear, inquisitive reader. Never!&lt;/p&gt;

&lt;p&gt;Now that we&amp;#39;ve compiled our Clojure program, let&amp;#39;s get it running:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# Notice that you have to provide a numerical argument&lt;/span&gt;
$ &lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;learn_a_language&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;important_phrases&lt;/span&gt; 0
&lt;span class="n"&gt;English&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="no"&gt;I&lt;/span&gt; &lt;span class="n"&gt;love&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;German&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;Ich&lt;/span&gt; &lt;span class="n"&gt;liebe&lt;/span&gt; &lt;span class="n"&gt;dich&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

$ &lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;learn_a_language&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;important_phrases&lt;/span&gt; 3
&lt;span class="n"&gt;English&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;Pass&lt;/span&gt; &lt;span class="n"&gt;me&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;mustard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;German&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;Gib&lt;/span&gt; &lt;span class="n"&gt;mir&lt;/span&gt; &lt;span class="n"&gt;den&lt;/span&gt; &lt;span class="n"&gt;Senf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Success! You are now ready to express your love for Leiningen in its
native tongue. I highly recommend you use this program to come up with
tweets to send to @technomancy to express your appreciation.&lt;/p&gt;

&lt;p&gt;But before you do that, notice the classpath. We need to include both
the &lt;code&gt;classes&lt;/code&gt; directory, because that&amp;#39;s where the
&lt;code&gt;learn_a_language/important_phrases&lt;/code&gt; class files live, and
&lt;code&gt;clojure.jar&lt;/code&gt;, because the class files generated by &lt;code&gt;compile&lt;/code&gt; need to
be able to access Clojure class files.&lt;/p&gt;

&lt;p&gt;To sum up:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# load clojure repl&lt;/span&gt;
$ &lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="p"&gt;.:&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="c"&gt;# in Clojure repl&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;learn_a_language/important_phrases&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="err"&gt;learn-a-language.important-phrases)&lt;/span&gt;
&lt;span class="c"&gt;# back to command line&lt;/span&gt;
&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;learn_a_language&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;important_phrases&lt;/span&gt; 0
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I hope this brief foray into the world of manually building and
running a Clojure program has been educational. You can see how it
would be burdensome to go through his process over and over again
while developing a program. Let&amp;#39;s finally bring in our pal Leiningen
to automate this process.&lt;/p&gt;

&lt;h2&gt;How Leiningen Compiles and Runs a Basic Clojure Program&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s build the &amp;quot;learn a language&amp;quot; program with Leiningen. We have a
very basic project at &lt;code&gt;make-a-clojure-baby/leiningen/lein-build&lt;/code&gt;.
Under that the directory, the file
&lt;code&gt;src/learn_a_language/important_phrases.clj&lt;/code&gt; is the same as the one
listed above.&lt;/p&gt;

&lt;h3&gt;lein run&lt;/h3&gt;

&lt;p&gt;Lein automates the build + run process with &lt;code&gt;lein run&lt;/code&gt;. Go ahead and
try that now:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;$ &lt;span class="n"&gt;lein&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; 2
&lt;span class="n"&gt;Compiling&lt;/span&gt; &lt;span class="n"&gt;learn&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;important&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;phrases&lt;/span&gt;
&lt;span class="n"&gt;English&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;miss&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;German&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;Ich&lt;/span&gt; &lt;span class="n"&gt;vermisse&lt;/span&gt; &lt;span class="n"&gt;dich&lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;Du&lt;/span&gt; &lt;span class="n"&gt;fehlst&lt;/span&gt; &lt;span class="n"&gt;mir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can probably guess what&amp;#39;s happening at this point, at least to a
degree. Leiningen is compiling &lt;code&gt;important_phrases.clj&lt;/code&gt; resulting in a
number of Java &lt;code&gt;.class&lt;/code&gt; files. We can, in fact, see these class files:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;$ &lt;span class="n"&gt;ls&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;learn_a_language&lt;/span&gt;
&lt;span class="n"&gt;important_phrases&lt;/span&gt;$&lt;span class="n"&gt;_main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;span class="n"&gt;important_phrases&lt;/span&gt;$&lt;span class="n"&gt;loading__4784__auto__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;span class="n"&gt;important_phrases__init&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Leiningen then somehow constructs a classpath such that both Clojure
and the &amp;quot;important phrases&amp;quot; classes are accessible by Java. Finally,
the &lt;code&gt;-main&lt;/code&gt; function is executed.&lt;/p&gt;

&lt;p&gt;I know what you&amp;#39;re thinking at this point, noble reader. You&amp;#39;re
thinking that the &amp;quot;somehow&amp;quot; in &amp;quot;somehow constructs a classpath&amp;quot; is a
particularly un-manly, un-artistic, un-mustached, un-sparkly word,
unbefitting an article on Leiningen. And you are absolutely right. To
avoid your wrath, let&amp;#39;s dig into Leiningen&amp;#39;s source code so that we
can understand what&amp;#39;s going on with complete clarity.&lt;/p&gt;

&lt;h3&gt;Walking Through &amp;quot;lein run&amp;quot;&lt;/h3&gt;

&lt;p&gt;To get an idea of where to start, let&amp;#39;s run &lt;code&gt;lein run 1&lt;/code&gt; again and
then run &lt;code&gt;ps | grep lein&lt;/code&gt;. The output has been broken up to make more
sense (apologies for the goofy highlighting):&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# you can actually copy and paste the part after the PID to try this&lt;/span&gt;
&lt;span class="c"&gt;# in your terminal&lt;/span&gt;
8420 &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;TieredCompilation&lt;/span&gt;  &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Xbootclasspath&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;installs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;2&lt;span class="p"&gt;.&lt;/span&gt;0&lt;span class="p"&gt;.&lt;/span&gt;0&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;UTF&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;8 &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dmaven&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wagon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;easy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dleiningen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;web_sites&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dleiningen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;installs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;2&lt;span class="p"&gt;.&lt;/span&gt;0&lt;span class="p"&gt;.&lt;/span&gt;0&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt; `&lt;span class="c"&gt;# clojure.main is the entry point` \&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;run&lt;/span&gt; 1

8432 &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  `&lt;span class="c"&gt;# your classpath will be different` \&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;web_sites&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;web_sites&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;web_sites&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;web_sites&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;web_sites&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;1&lt;span class="p"&gt;.&lt;/span&gt;5&lt;span class="p"&gt;.&lt;/span&gt;1&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;1&lt;span class="p"&gt;.&lt;/span&gt;5&lt;span class="p"&gt;.&lt;/span&gt;1&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;XX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;TieredCompilation&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dclojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;daniel&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;web_sites&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;leiningen&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lein&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dlearn&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;version&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;0&lt;span class="p"&gt;.&lt;/span&gt;1&lt;span class="p"&gt;.&lt;/span&gt;0&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SNAPSHOT&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;UTF&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;8 &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Dclojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
  &lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt; `&lt;span class="c"&gt;# clojure.main is the entry point` \&lt;/span&gt;
  `&lt;span class="c"&gt;# this next part specifies code to be evaluated by Clojure` \&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;e&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;require&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;learn-a-language.important-phrases) \&lt;/span&gt;
&lt;span class="s"&gt;       (catch java.io.FileNotFoundException ___6081__auto__)) \&lt;/span&gt;
&lt;span class="s"&gt;      (set! *warn-on-reflection* nil) \&lt;/span&gt;
&lt;span class="s"&gt;      (clojure.core/let \&lt;/span&gt;
&lt;span class="s"&gt;       [v__6079__auto__ \&lt;/span&gt;
&lt;span class="s"&gt;        (clojure.core/resolve &amp;#39;&lt;/span&gt;&lt;span class="n"&gt;learn&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;important&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;phrases&lt;/span&gt;&lt;span class="o"&gt;/-&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ifn&lt;/span&gt;? &lt;span class="n"&gt;v__6079__auto__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v__6079__auto__&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reflector&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;invokeStaticMethod&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
         &lt;span class="s"&gt;&amp;quot;learn-a-language.important-phrases&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
         &lt;span class="s"&gt;&amp;quot;main&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;into&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;
          &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;into&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="err"&gt;(&amp;quot;1&amp;quot;))])))))&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There are two things happening here. When you first run &lt;code&gt;lein run&lt;/code&gt;,
then the process with PID 8420 starts. There are a lot of
configuration variables that we don&amp;#39;t necessarily need to care about.
What&amp;#39;s essentially happening is we&amp;#39;re saying:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start up the JVM with the leiningen standalone jar on the classpath&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;clojure.main&lt;/code&gt; as the Java entry point&lt;/li&gt;
&lt;li&gt;Pass &lt;code&gt;-m leiningen.core.main run 1&lt;/code&gt; as arguments to &lt;code&gt;clojure.main&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last step specifies the &lt;em&gt;Clojure&lt;/em&gt; entry point, as opposed to the
&lt;em&gt;Java&lt;/em&gt; entry point. Clojure uses it to load the &lt;code&gt;leiningen.core.main&lt;/code&gt;
namespace and then execute the &lt;code&gt;-main&lt;/code&gt; function within it.
&lt;code&gt;leiningen.core.main/-main&lt;/code&gt; receives the arguments &lt;code&gt;run 1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can view Leiningen&amp;#39;s &lt;code&gt;leiningen.core.main/-main&lt;/code&gt; function
&lt;a href="https://github.com/technomancy/leiningen/blob/master/leiningen-core/src/leiningen/core/main.clj#L275"&gt;on github&lt;/a&gt;:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;-main&lt;/span&gt;
  &lt;span class="s"&gt;&amp;quot;Command-line entry point.&amp;quot;&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;raw-args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;try&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;user/init&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;project &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;project/init-project&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.exists&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;io/file&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;project.clj&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;project/read&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;assoc &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;project/make&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;user/profiles&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
                       &lt;span class="ss"&gt;:eval-in&lt;/span&gt; &lt;span class="ss"&gt;:leiningen&lt;/span&gt; &lt;span class="ss"&gt;:prep-tasks&lt;/span&gt; &lt;span class="p"&gt;[])))&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;task-name&lt;/span&gt; &lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;task-args&lt;/span&gt; &lt;span class="nv"&gt;raw-args&lt;/span&gt; &lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:min-lein-version&lt;/span&gt; &lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;verify-min-version&lt;/span&gt; &lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;configure-http&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;warn-chaining&lt;/span&gt; &lt;span class="nv"&gt;task-name&lt;/span&gt; &lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;apply-task&lt;/span&gt; &lt;span class="nv"&gt;task-name&lt;/span&gt; &lt;span class="nb"&gt;project &lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;catch&lt;/span&gt; &lt;span class="nv"&gt;Exception&lt;/span&gt; &lt;span class="nv"&gt;e&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;or &lt;/span&gt;&lt;span class="nv"&gt;*debug*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;not &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:exit-code&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ex-data&lt;/span&gt; &lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.printStackTrace&lt;/span&gt; &lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when-not &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:suppress-msg&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ex-data&lt;/span&gt; &lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.getMessage&lt;/span&gt; &lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:exit-code&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ex-data&lt;/span&gt; &lt;span class="nv"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Just as we would suspect from the &lt;code&gt;ps&lt;/code&gt; output, this is the command
line entry point for &lt;code&gt;lein&lt;/code&gt;. One of the first things this function
does is figure out your project configuration from your &lt;code&gt;project.clj&lt;/code&gt;
file. Here&amp;#39;s ours:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defproject &lt;/span&gt;&lt;span class="nv"&gt;learn-a-language&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.1.0-SNAPSHOT&amp;quot;&lt;/span&gt;
  &lt;span class="ss"&gt;:description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;FIXME: write description&amp;quot;&lt;/span&gt;
  &lt;span class="ss"&gt;:url&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;http://example.com/FIXME&amp;quot;&lt;/span&gt;
  &lt;span class="ss"&gt;:license&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Eclipse Public License&amp;quot;&lt;/span&gt;
            &lt;span class="ss"&gt;:url&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;http://www.eclipse.org/legal/epl-v10.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="ss"&gt;:dependencies&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;org.clojure/clojure&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1.5.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
  &lt;span class="ss"&gt;:main&lt;/span&gt; &lt;span class="nv"&gt;learn-a-language.important-phrases&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The most important line, for our purposes, is&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="ss"&gt;:main&lt;/span&gt; &lt;span class="nv"&gt;learn-a-language.important-phrases&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This tells Leiningen what function to execute when you run &lt;code&gt;lein run&lt;/code&gt;.
If you specify a namespace without a function, as we do above, then
Leiningen defaults to using the &lt;code&gt;-main&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Next, if you look about 2/3 of the way down in the
&lt;code&gt;leiningen.core.main/-main&lt;/code&gt; function, you&amp;#39;ll see the &lt;code&gt;apply-task&lt;/code&gt;
function being called. This calls &lt;code&gt;resolve-task&lt;/code&gt; which eventually
resolves to &lt;code&gt;leiningen.run&lt;/code&gt;, which you can
&lt;a href="https://github.com/technomancy/leiningen/blob/master/src/leiningen/run.clj"&gt;also see on github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is pretty cool &amp;mdash; &lt;code&gt;run&lt;/code&gt; is just another task from
Leiningen&amp;#39;s point of view. Wait... did I just say &amp;quot;cool&amp;quot;? I meant
&lt;em&gt;MANLY&lt;/em&gt; and &lt;em&gt;ARTISTIC&lt;/em&gt; and &lt;em&gt;SPARKLY&lt;/em&gt;. But yeah, it looks like basic
leiningen architecture includes the &lt;code&gt;leiningen.core&lt;/code&gt; collection of
namespaces, which handle task resolution and application, and plain
ol&amp;#39; &lt;code&gt;leiningen&lt;/code&gt;, which appears to be mostly a collection of default
tasks.&lt;/p&gt;

&lt;p&gt;Leiningen uses this same mechanism to execute any function in your
Clojure project as a task. Bodacious! I recommend checking out
&lt;a href="https://github.com/technomancy/leiningen/tree/master/src/leiningen"&gt;the code for the other Leiningen tasks&lt;/a&gt;.
You&amp;#39;ll see how they do more than just require and run a single
function, but the task-running infrastructure remains the same.&lt;/p&gt;

&lt;p&gt;Anyway, once the &lt;code&gt;run&lt;/code&gt; task has been resolved, it is executed and the
result is the second process we saw in the &lt;code&gt;ps | grep lein&lt;/code&gt; output
above, the process with PID 8432. A sub-process is created to enforce
isolation between Leiningen and your project. I won&amp;#39;t go into how the
command for the sub-process gets constructed, as you can figure that
all out from &lt;code&gt;leiningen/run&lt;/code&gt;. What&amp;#39;s more important is what it
actually does. The command loads Clojure and tells it to evaluate the
following:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;try&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;clojure.core/require&lt;/span&gt; &lt;span class="ss"&gt;&amp;#39;learn-a-language.important-phrases&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;catch&lt;/span&gt; &lt;span class="nv"&gt;java.io.FileNotFoundException&lt;/span&gt; &lt;span class="nv"&gt;___6081__auto__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set!&lt;/span&gt; &lt;span class="nv"&gt;*warn-on-reflection*&lt;/span&gt; &lt;span class="nv"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;clojure.core/let&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;v__6079__auto__&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;clojure.core/resolve&lt;/span&gt; &lt;span class="ss"&gt;&amp;#39;learn-a-language.important-phrases/-main&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;if&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;clojure.core/ifn?&lt;/span&gt; &lt;span class="nv"&gt;v__6079__auto__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;v__6079__auto__&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;clojure.lang.Reflector/invokeStaticMethod&lt;/span&gt;
       &lt;span class="s"&gt;&amp;quot;learn-a-language.important-phrases&amp;quot;&lt;/span&gt;
       &lt;span class="s"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;clojure.core/into-array&lt;/span&gt;
        &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;clojure.core/into-array&lt;/span&gt; &lt;span class="nv"&gt;java.lang.String&lt;/span&gt; &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))])))))&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can see how the end result is that
&lt;code&gt;learn-a-language.important-phrases/-main&lt;/code&gt; gets executed with the
argument &lt;code&gt;&amp;quot;1&amp;quot;&lt;/code&gt;. One interesting thing to note about this approach is
that the &lt;code&gt;:gen-class&lt;/code&gt; directive isn&amp;#39;t actually needed. In the manual
build at the beginning of this article, we needed &lt;code&gt;:gen-class&lt;/code&gt; because
we were specifying &lt;code&gt;learn-a-language.important-phrases&lt;/code&gt; as the JVM
entry point. When we use &lt;code&gt;lein run&lt;/code&gt;, the entry point is
&lt;code&gt;clojure.main&lt;/code&gt;. Once Clojure is loaded, we use it to evaluate some
code which loads the &lt;code&gt;learn-a-language.important-phrases&lt;/code&gt; namespace
and then calls the &lt;code&gt;-main&lt;/code&gt; function.&lt;/p&gt;

&lt;h2&gt;Wrapping Things Up&lt;/h2&gt;

&lt;p&gt;So now we know how Leiningen compiles and runs a basic Clojure
program! Can you feel your mustache growing? Can you feel your
artistry blooming? Are you feeling just a smidge more sparklier? I
sure hope so!&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s everything we covered:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building and running a Clojure program manually:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load the Clojure repl&lt;/li&gt;
&lt;li&gt;Load your Clojure code (make sure it includes &lt;code&gt;:gen-class&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Compile your Clojure code. By default code gets put in &lt;code&gt;classes&lt;/code&gt;
directory&lt;/li&gt;
&lt;li&gt;Run your code, making sure the classpath includes the &lt;code&gt;classes&lt;/code&gt;
directory and &lt;code&gt;clojure.jar&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# load clojure repl&lt;/span&gt;
$ &lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="p"&gt;.:&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="c"&gt;# in Clojure repl&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;learn_a_language/important_phrases&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="err"&gt;learn-a-language.important-phrases)&lt;/span&gt;
&lt;span class="c"&gt;# back to command line&lt;/span&gt;
&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;learn_a_language&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;important_phrases&lt;/span&gt; 0
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Building and running a Clojure program with Leiningen:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;lein run&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Magic!

&lt;ul&gt;
&lt;li&gt;Start Java with &lt;code&gt;clojure.main&lt;/code&gt; as the entry point&lt;/li&gt;
&lt;li&gt;Execute the &lt;code&gt;leiningen.core/-main&lt;/code&gt; function

&lt;ul&gt;
&lt;li&gt;Setup project config with &lt;code&gt;project.clj&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Resolve the task to be run&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Run the task

&lt;ul&gt;
&lt;li&gt;Automagically set the classpath&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;clojure.main&lt;/code&gt; as the Java entry point&lt;/li&gt;
&lt;li&gt;Construct some Clojure code to evaluate so that the
project&amp;#39;s main function gets executed. This happens in a
sub-process to enforce isolcation from Leiningen. Check out
Leiningen&amp;#39;s &lt;code&gt;eval-in-project&lt;/code&gt; function for more info.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next article we&amp;#39;ll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How Leiningen avoids waste with a trampoline&lt;/li&gt;
&lt;li&gt;How Leiningen manages dependencies&lt;/li&gt;
&lt;li&gt;How to distribute a full application&lt;/li&gt;
&lt;li&gt;How to distribute a library&lt;/li&gt;
&lt;li&gt;Manliness&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you enjoyed this article. Please do leave me any feedback - I&amp;#39;m
always looking for ways to improve my writing!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2013-03-13:/programming/how-clojure-babies-are-made-the-java-cycle/</id>
    <title type="html">How Clojure Babies Are Made: Compiling and Running a Java Program</title>
    <published>2013-03-13T04:23:00Z</published>
    <updated>2013-03-13T04:23:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/programming/how-clojure-babies-are-made-the-java-cycle/" />
    <content type="html">&lt;p&gt;If you&amp;#39;re at all like me, the moment you got your first Clojure
program running you belted out, &amp;quot;SOOO MUUUUUUUCH POOOOOOOWEEEEEEEER!&amp;quot;
and thrust one or both fists into the air. Then, fifteen minutes
later, you found yourself muttering things like &amp;quot;What&amp;#39;s a maven?&amp;quot; and
&amp;quot;Classpath what now?&amp;quot; and &amp;quot;What is Leiningen actually doing, anyway?
Sure, those are the most handsome mustaches I ever laid eyes on, but
can I really trust them?&amp;quot;&lt;/p&gt;

&lt;p&gt;This post is here to help you out. In it, I will describe how Java
compiles and runs programs, and how this relates to Clojure. In an
upcoming post, I will also describe how Leiningen makes this process
way easier. Here&amp;#39;s an outline of what&amp;#39;s to come:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java

&lt;ul&gt;
&lt;li&gt;Compilation

&lt;ul&gt;
&lt;li&gt;javac&lt;/li&gt;
&lt;li&gt;Class lookup rules &amp;amp; classpath&lt;/li&gt;
&lt;li&gt;imports&lt;/li&gt;
&lt;li&gt;packages&lt;/li&gt;
&lt;li&gt;JAR files&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Running

&lt;ul&gt;
&lt;li&gt;Class file&lt;/li&gt;
&lt;li&gt;classpath&lt;/li&gt;
&lt;li&gt;Executable JAR&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Leiningen

&lt;ul&gt;
&lt;li&gt;Running an app without Leiningen&lt;/li&gt;
&lt;li&gt;classpath management&lt;/li&gt;
&lt;li&gt;Incorporating Clojure automatically&lt;/li&gt;
&lt;li&gt;Dependency managemenet&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Update: Part 2 of this series is
&lt;a href="/programming/how-clojure-babies-are-made-lein-run/"&gt;now available&lt;/a&gt;!)&lt;/p&gt;

&lt;h2&gt;Java&lt;/h2&gt;

&lt;p&gt;Java is going to rule the universe. The sooner you accept that, the
better. If you don&amp;#39;t have the
&lt;a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html"&gt;JDK installed&lt;/a&gt;
installed, you might want to do that now. To check, just try running
&lt;code&gt;java&lt;/code&gt; and &lt;code&gt;javac&lt;/code&gt; in your terminal. By the way - this post assumes
you&amp;#39;re somewhat familiar with the terminal. It also assumes you&amp;#39;re
familiar with object-oriented programming.&lt;/p&gt;

&lt;h2&gt;Compiling and Running a Basic Program&lt;/h2&gt;

&lt;p&gt;This section will lay a foundation for your understanding of Java. It
doesn&amp;#39;t address Clojure directly, but the knowledge you gain will be
useful in your Clojuring.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s put our game faces on and start with a basic program. Visit the
&lt;a href="https://github.com/flyingmachine/make-a-clojure-baby"&gt;github repo&lt;/a&gt;
for the examples in this post and clone that baby for all you&amp;#39;re
worth.&lt;/p&gt;

&lt;p&gt;In the folder &lt;code&gt;ShiverMeTimbers&lt;/code&gt;, you should find an article named
&lt;code&gt;ShiverMeTimbers.java&lt;/code&gt;. Here are its contents:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShiverMeTimbers&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Shiver me timbers!!!&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once you&amp;#39;ve recovered from your swoon, &lt;code&gt;cd&lt;/code&gt; to &lt;code&gt;ShiverMeTimbers&lt;/code&gt; and
run &lt;code&gt;javac ShiverMeTimbers.java&lt;/code&gt;. If you typed everything correctly
&lt;em&gt;and&lt;/em&gt; you&amp;#39;re pure of heart, you should now see a file named
&lt;code&gt;ShiverMeTimbers.class&lt;/code&gt;.&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ls
ShiverMeTimbers.class ShiverMeTimbers.java
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You&amp;#39;ve just compiled your first Java program, son! Now run it with
&lt;code&gt;java ShiverMeTimbers&lt;/code&gt;. You should see:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Shiver&lt;/span&gt; &lt;span class="n"&gt;me&lt;/span&gt; &lt;span class="n"&gt;timbers&lt;/span&gt;!!!
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Which I&amp;#39;m pretty sure is like the Lord&amp;#39;s prayer, but for pirates.
Anyway, what&amp;#39;s happening here is you used the Java compiler, &lt;code&gt;javac&lt;/code&gt;,
to create a Java class file, &lt;code&gt;ShiverMeTimbers.class&lt;/code&gt;. This file is
packed with oodles of Java bytecode which the
&lt;a href="http://en.wikipedia.org/wiki/Java_virtual_machine"&gt;Java Virtual Machine&lt;/a&gt;
executes when running a program.&lt;/p&gt;

&lt;p&gt;When you ran &lt;code&gt;java ShiverMeTimbers&lt;/code&gt;, the JVM first looked on your
&lt;code&gt;classpath&lt;/code&gt; for a class named &lt;code&gt;ShiverMeTimbers&lt;/code&gt;. In Java, you&amp;#39;re only
allowed to have one public class per file and the filename and class
name must be the same. This is how &lt;code&gt;java&lt;/code&gt; knows to try looking in
&lt;code&gt;ShiverMeTimbers.class&lt;/code&gt; for the ShiverMeTimbers class&amp;#39;s bytecode.&lt;/p&gt;

&lt;p&gt;Also, by default, the &lt;code&gt;classpath&lt;/code&gt; includes the directory &lt;code&gt;.&lt;/code&gt;, or the
current directory. Try running &lt;code&gt;java -classpath /tmp ShiverMeTimbers&lt;/code&gt;
and you will get an error, even though &lt;code&gt;ShiverMeTimbers.class&lt;/code&gt; is
right there in the same directory.&lt;/p&gt;

&lt;p&gt;After &lt;code&gt;java&lt;/code&gt; found the bytecode for the &lt;code&gt;ShiverMeTimbers&lt;/code&gt; class, it
executed that class&amp;#39;s &lt;code&gt;main&lt;/code&gt; method. Java&amp;#39;s kind of like C that way,
in that whenever you say &amp;quot;run something, and use this class as your
entry point&amp;quot;, it always will run that class&amp;#39;s &lt;code&gt;main&lt;/code&gt; method. Which
means that that method has to be &lt;code&gt;public&lt;/code&gt;, as you can see above.
(&lt;a href="http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html"&gt;Here&amp;#39;s more info on Java&amp;#39;s access modifiers&lt;/a&gt;
if you&amp;#39;re curious.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Ideas&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;javac&lt;/code&gt; compiles java source code to bytecode which the JVM can
execute&lt;/li&gt;
&lt;li&gt;&lt;code&gt;java&lt;/code&gt; searches the &lt;code&gt;classpath&lt;/code&gt; for the class you specified and
executes its &lt;code&gt;main&lt;/code&gt; method. That method must be public.&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next section you&amp;#39;ll learn about handling program code that&amp;#39;s
spread over more than one file. If you don&amp;#39;t remove your socks now,
they&amp;#39;re liable to get knocked off!&lt;/p&gt;

&lt;h2&gt;Packages and Imports&lt;/h2&gt;

&lt;p&gt;In this section, you&amp;#39;ll learn about how Java handles programs which
are spread over more than one file. You&amp;#39;ll also learn how to use Java
libraries. Once again, we&amp;#39;ll look at both compiling and running a
program. This section has direct implications for Clojure programming,
so pay attention!&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s start with a couple definitions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;package:&lt;/strong&gt; Similar to Clojure&amp;#39;s namespaces, packages serve two
purposes. They provide code organization, just like clojure
namespaces. They also enforce access rules, which we don&amp;#39;t really
care about. The directory that a Java file lives in must mirror the
package it belongs to. If a file has the line &lt;code&gt;package com.shapemaster&lt;/code&gt;
in it, then it must be located at &lt;code&gt;com/shapemaster&lt;/code&gt; somewhere on your
classpath. More about classpath later.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;import:&lt;/strong&gt; Java allows you to import classes, which basically means
that you can refer to them without using their namespace prefix. So,
if you have a class in &lt;code&gt;com.shapemaster&lt;/code&gt; named &lt;code&gt;Square&lt;/code&gt;, you could
write &lt;code&gt;import com.shapemaster.Square;&lt;/code&gt; or &lt;code&gt;import com.shapemaster.*;&lt;/code&gt;
at the top of a &lt;code&gt;.java&lt;/code&gt; file so that you can use &lt;code&gt;Square&lt;/code&gt; in your
code instead of &lt;code&gt;com.shapemaster.Square&lt;/code&gt;. Code example below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let&amp;#39;s see &lt;code&gt;package&lt;/code&gt; and &lt;code&gt;import&lt;/code&gt; in action. Here they are as used
by the files in 
&lt;code&gt;make-a-clojure-baby/ContrivedPackageExample&lt;/code&gt;. Pay
attention to the comments, as they explain a lot of what&amp;#39;s going on&lt;/p&gt;

&lt;p&gt;Contents of &lt;code&gt;make-a-clojure-baby/ContrivedPackageExample/Conversation.java&lt;/code&gt;:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Conversation&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;    
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// The &amp;quot;ns1&amp;quot; prefix is necessary because ShyGhost belongs to&lt;/span&gt;
        &lt;span class="c1"&gt;// the &amp;quot;ns1&amp;quot; package, and we haven&amp;#39;t imported the classes in&lt;/span&gt;
        &lt;span class="c1"&gt;// that package&lt;/span&gt;
        &lt;span class="n"&gt;ns1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ShyGhost&lt;/span&gt; &lt;span class="n"&gt;shyGhost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ns1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ShyGhost&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;shyGhost&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;talk&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Contents of &lt;code&gt;make-a-clojure-baby/ContrivedPackageExample/ns1/ShyGhost.java&lt;/code&gt;:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;// The classes defined in this file belong to the &amp;quot;ns1&amp;quot; package.&lt;/span&gt;
&lt;span class="c1"&gt;// Notice that this file is in the &amp;quot;ns1&amp;quot; directory.&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="n"&gt;ns1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// This basically means, &amp;quot;I hate typing the namespace prefix all the&lt;/span&gt;
&lt;span class="c1"&gt;// time so please allow me to not do that&amp;quot;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;ns2.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShyGhost&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;talk&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// the shy ghost can&amp;#39;t speak for himself and has to get&lt;/span&gt;
        &lt;span class="c1"&gt;// someone else to do it for him&lt;/span&gt;

        &lt;span class="c1"&gt;// Notice that even though SuperManlyIguana belongs to the ns2&lt;/span&gt;
        &lt;span class="c1"&gt;// namespace, we don&amp;#39;t have to use the ns2 prefix&lt;/span&gt;
        &lt;span class="n"&gt;SuperManlyIguana&lt;/span&gt; &lt;span class="n"&gt;smi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SuperManlyIguana&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;smi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;talk&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Contents of &lt;code&gt;make-a-clojure-baby/ContrivedPackageExample/ns2/SuperManlyIguana.java&lt;/code&gt;:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;// The classes defined in this file belong to the &amp;quot;ns2&amp;quot; package&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="n"&gt;ns2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SuperManlyIguana&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;talk&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Why hello there&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can run all the above code with the following:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ContrivedPackageExample&lt;/span&gt;
&lt;span class="n"&gt;javac&lt;/span&gt; &lt;span class="n"&gt;Conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="n"&gt;Conversation&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Can you guess what this outputs? I bet you can!&lt;/p&gt;

&lt;p&gt;Anyway, so far we&amp;#39;ve established the relationship between importing,
packages, and directory structure: Packages organize code and require
a matching directory structure. Importing classes allows you to
&amp;quot;de-namespace&amp;quot; them.&lt;/p&gt;

&lt;p&gt;One piece that&amp;#39;s missing, which I alluded to above, is the role of the
classpath. Try the following:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ContrivedPackageExample&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ns1&lt;/span&gt;
&lt;span class="n"&gt;javac&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;Conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Boom! The Java compiler just told you to hang your head in shame, and
maybe weep a little:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;../Conversation.java:13: error: package ns1 does not exist&lt;/span&gt;
&lt;span class="cp"&gt;        ns1.ShyGhost shyGhost = new ns1.ShyGhost();&lt;/span&gt;
&lt;span class="cp"&gt;           ^&lt;/span&gt;
&lt;span class="cp"&gt;../Conversation.java:13: error: package ns1 does not exist&lt;/span&gt;
&lt;span class="cp"&gt;        ns1.ShyGhost shyGhost = new ns1.ShyGhost();&lt;/span&gt;
&lt;span class="cp"&gt;                                       ^&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It thinks that the &lt;code&gt;ns1&lt;/code&gt; package doesn&amp;#39;t exist. But that&amp;#39;s stupid,
right? I mean, you&amp;#39;re in the &lt;code&gt;ns1&lt;/code&gt; directory and everything!&lt;/p&gt;

&lt;p&gt;What&amp;#39;s happening here is that the java compiler is looking for
&lt;code&gt;./ns1/ShyGhost&lt;/code&gt; which it can&amp;#39;t find because you&amp;#39;re already in the
&lt;code&gt;ns1&lt;/code&gt; directory. This is because the default classpath includes &amp;#39;.&amp;#39;.
Without changing directories, try running &lt;code&gt;javac -classpath ../
../Conversation.java&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Et voila! It works! So let&amp;#39;s amend our understanding of the
relationship between importing, packages, and the directory
structures: when you&amp;#39;re compiling a Java program, Java searches your
classpath for packages.&lt;/p&gt;

&lt;p&gt;Guess what: the same things happens when you&amp;#39;re running a Java
program, too. Run the following:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ContrivedPackageExample&lt;/span&gt;
&lt;span class="n"&gt;mkdir&lt;/span&gt; &lt;span class="n"&gt;hide&lt;/span&gt;
&lt;span class="n"&gt;mv&lt;/span&gt; &lt;span class="n"&gt;ns1&lt;/span&gt; &lt;span class="n"&gt;hide&lt;/span&gt;
&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="n"&gt;Conversation&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Another explosion! Now try:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="p"&gt;.:&lt;/span&gt;&lt;span class="n"&gt;hide&lt;/span&gt; &lt;span class="n"&gt;Converstaion&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Success!&lt;/p&gt;

&lt;p&gt;I hope this clarifies the relationship between your directory
structure, the classpath, packages, and importing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Ideas&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Packages provide a way for you to organize classes. Your directory
structure must reflect your package names&lt;/li&gt;
&lt;li&gt;Imports allow you to be lazy and not prefix a class name with its
package&lt;/li&gt;
&lt;li&gt;&lt;code&gt;javac&lt;/code&gt; and &lt;code&gt;java&lt;/code&gt; search the classpath for packages&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;JAR Files&lt;/h2&gt;

&lt;p&gt;JAR, or Java ARchive, files allow you to bundle all your .class files
into one single file. Run the following:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;baby&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ContrivedPackageExample&lt;/span&gt;
&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;cvfe&lt;/span&gt; &lt;span class="n"&gt;contrived&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;Conversation&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="o"&gt;*/*&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;contrived&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It works, just like before. You bundled all the class files into
&lt;code&gt;contrived.jar&lt;/code&gt; with the file patterns &lt;code&gt;*.class&lt;/code&gt; and &lt;code&gt;ns*/*.class&lt;/code&gt;.
You also indicated that the &lt;code&gt;Conversation&lt;/code&gt; class is the &amp;quot;entry point&amp;quot;
with the &lt;code&gt;e&lt;/code&gt; flag. The &amp;quot;entry point&amp;quot; is the class which contains the
&lt;code&gt;main&lt;/code&gt; method which should be executed when the JAR as a whole is run.&lt;/p&gt;

&lt;p&gt;Behind the scenes, java knows which class is the entry point because
when you create a jar, the file &lt;code&gt;META-INF/MANIFEST.MF&lt;/code&gt; automaticaally
gets generated and added. When you add the &lt;code&gt;e&lt;/code&gt; flag, the following
line gets added:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Main&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Conversation&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;By the way, you might be wondering why Java isn&amp;#39;t throwing any
exceptions like &amp;quot;can&amp;#39;t find package&amp;quot;. The reason is that the JAR file
maintains the directory structure. You can see its contents with:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt; &lt;span class="n"&gt;contrived&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You&amp;#39;ll see that the directory structure is maintained.&lt;/p&gt;

&lt;p&gt;One final point: a JAR file is really just a Zip file with a &amp;quot;.jar&amp;quot;
extension. You can treat it just the same as any other zip file.&lt;/p&gt;

&lt;h2&gt;Pulling it All Together: clojure.jar&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s pull all of this together with some Clojure! Download
&lt;a href="http://repo1.maven.org/maven2/org/clojure/clojure/1.5.1/clojure-1.5.1.zip"&gt;the 1.5.1 stable release&lt;/a&gt;
and unzip it. Then &lt;code&gt;cd&lt;/code&gt; to the directory that gets created and run&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;java&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;1&lt;span class="p"&gt;.&lt;/span&gt;5&lt;span class="p"&gt;.&lt;/span&gt;1&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You should get that most soothing of sights, the Clojure REPL. So, how
did it actually start up? Let&amp;#39;s have a look at &lt;code&gt;META-INF/MANIFEST.MF&lt;/code&gt;
in the jar file:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Manifest&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 1&lt;span class="p"&gt;.&lt;/span&gt;0
&lt;span class="n"&gt;Archiver&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Plexus&lt;/span&gt; &lt;span class="n"&gt;Archiver&lt;/span&gt;
&lt;span class="n"&gt;Created&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Apache&lt;/span&gt; &lt;span class="n"&gt;Maven&lt;/span&gt;
&lt;span class="n"&gt;Built&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hudson&lt;/span&gt;
&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Jdk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 1&lt;span class="p"&gt;.&lt;/span&gt;6&lt;span class="p"&gt;.&lt;/span&gt;0&lt;span class="n"&gt;_20&lt;/span&gt;
&lt;span class="n"&gt;Main&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It looks like &lt;code&gt;clojure.main&lt;/code&gt; is specified as the entry point. Where
does this class come from? Well, have a look at
&lt;a href="https://github.com/clojure/clojure/blob/master/src/jvm/clojure/main.java"&gt;clojure/main.java on github&lt;/a&gt;:&lt;/p&gt;
&lt;div class='code pygments'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; *   Copyright (c) Rich Hickey. All rights reserved.&lt;/span&gt;
&lt;span class="cm"&gt; *   The use and distribution terms for this software are covered by the&lt;/span&gt;
&lt;span class="cm"&gt; *   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)&lt;/span&gt;
&lt;span class="cm"&gt; *   which can be found in the file epl-v10.html at the root of this distribution.&lt;/span&gt;
&lt;span class="cm"&gt; *   By using this software in any fashion, you are agreeing to be bound by&lt;/span&gt;
&lt;span class="cm"&gt; *   the terms of this license.&lt;/span&gt;
&lt;span class="cm"&gt; *   You must not remove this notice, or any other, from this software.&lt;/span&gt;
&lt;span class="cm"&gt; **/&lt;/span&gt;

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="n"&gt;clojure&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;clojure.lang.Symbol&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;clojure.lang.Var&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;clojure.lang.RT&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;main&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Symbol&lt;/span&gt; &lt;span class="n"&gt;CLOJURE_MAIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;intern&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;clojure.main&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Var&lt;/span&gt; &lt;span class="n"&gt;REQUIRE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;clojure.core&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;require&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Var&lt;/span&gt; &lt;span class="n"&gt;LEGACY_REPL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;clojure.main&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;legacy-repl&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Var&lt;/span&gt; &lt;span class="n"&gt;LEGACY_SCRIPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;clojure.main&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;legacy-script&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Var&lt;/span&gt; &lt;span class="n"&gt;MAIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;clojure.main&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;legacy_repl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;REQUIRE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CLOJURE_MAIN&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;LEGACY_REPL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;legacy_script&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;REQUIRE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CLOJURE_MAIN&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;LEGACY_SCRIPT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;REQUIRE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CLOJURE_MAIN&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;MAIN&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;applyTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As you can see, the class &lt;code&gt;main&lt;/code&gt; is defined. It belongs to the package
&lt;code&gt;clojure&lt;/code&gt; and defines a &lt;code&gt;public static main&lt;/code&gt; method. This is all Java
needs to run a program.&lt;/p&gt;

&lt;p&gt;I hope this has helped clarify Java and how it relates to Clojure! In
my next post, I&amp;#39;ll dig in to Leiningen. Fun for everybody!!!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2013-02-28:/design/tapestry-conf/</id>
    <title type="html">Notes From Tapestry 2013</title>
    <published>2013-02-28T05:00:00Z</published>
    <updated>2013-02-28T05:00:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/design/tapestry-conf/" />
    <content type="html">&lt;p&gt;Yesterday I had the immense pleasure of joining about 100 other
designers, programmers, educators, data scientists, journalists and
storytellers in a day-long conference &amp;quot;designed to advance interactive
online storytelling with data.&amp;quot;&lt;/p&gt;

&lt;p&gt;Below is a list of links to many of the presentation examples followed
by notes on the presentations.
&lt;a href="https://github.com/flyingmachine/nanoc-blog/tree/master/content/design/tapestry-conf.md"&gt;You might like the way it&amp;#39;s presented on github&lt;/a&gt;
better - my blog isn&amp;#39;t ideal for this kind of content.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;d like to make any contributions
or corrections, please leave a comment, tweet me @nonrecursive, or
submit a pull request :)&lt;/p&gt;

&lt;h2&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://13pt.com/"&gt;13 point&lt;/a&gt;, the studio of Jonathan corum, an
information designer and science graphics editor at The New York
Times.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.nytimes.com/interactive/2012/08/04/sports/olympics/bob-beamons-long-olympic-shadow.html"&gt;Long jump olympic shadow video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;nolan reimold strike zone pitches video (I can&amp;#39;t find this one)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.nytimes.com/2011/02/15/science/15flea.html?_r=0"&gt;Flea power - how flees jump&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.nytimes.com/interactive/2012/11/02/us/politics/paths-to-the-white-house.html"&gt;512 paths to the white house&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.nytimes.com/interactive/2013/01/29/us/where-50000-guns-in-chicago-came-from.html?smid=tw-nytimes"&gt;where 50k guns in chicago came from&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.nytimes.com/interactive/2013/01/02/us/chicago-killings.html"&gt;A Chicago Divided by Killings&lt;/a&gt; A New York Times analysis of homicides and census data in Chicago compared areas near murders to those that were not. Residents living near homicides in the last 12 years were much more likely to be black, earn less money and lack a college degree.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://projects.nytimes.com/guantanamo"&gt;The Guantanamo Docket: A History of the Detainee Population&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://seattletimes.com/flatpages/specialreports/methadone/methadoneandthepoliticsofpain.html"&gt;Methadone and the Politics of Pain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://seattletimes.com/elephants/"&gt;Glamour Beasts: The dark side of elephant captivity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://seattletimes.com/html/specialreportspages/2019781508_interactive-the-tragic-family-tree-of-thonglaw.html"&gt;Interactive: The tragic family tree of Thonglaw&lt;/a&gt;
one of the interactive storytelling pieces associated with Glamour Beasts above&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.nytimes.com/2010/05/02/business/02metrics.html"&gt;Driving Shifts Into Reverse&lt;/a&gt;
unconventional mapping of time as a function of the x and y axes&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.nytimes.com/interactive/2012/09/17/science/driving-safety-in-fits-and-starts.html"&gt;Driving Safety, in Fits and Starts&lt;/a&gt;
same ideas as above&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.nytimes.com/projects/2012/snow-fall/#/?part=tunnel-creek"&gt;Snow Fall: The Avalanche at Tunnel Creek&lt;/a&gt; WOW&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.theinventionofhugocabret.com/index.htm"&gt;The Invention of Hugo Cabret&lt;/a&gt;
the book that inspired &amp;quot;Snow Fall&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;twenty eleven&amp;quot; no longer sure what this refers to&lt;/li&gt;
&lt;li&gt;&amp;quot;with olga&amp;quot; not sure what this refers to either&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/Chris-Ware/e/B001JOJLJ2"&gt;Chris Ware&lt;/a&gt; comic artist&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.perceptualedge.com/"&gt;Stephen Few&lt;/a&gt; leading thinker in
data viz&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pinterest.com/pin/61854194853193578/"&gt;Monstrous Costs, Nigel Holmes&lt;/a&gt;
controversial (?) chart&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.pollster.com/blogs/jobs_graph_large_feb10.php?nr=1"&gt;US job loss bar chart, bush administration vs. obama administration&lt;/a&gt;
clever to make the bars point downward - association downward with worse&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.nytimes.com/interactive/2009/11/06/business/economy/unemployment-lines.html"&gt;the jobless rate for people like you&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://grimace-project.net/"&gt;the grimace project&lt;/a&gt; - combine facial expressions&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/Influencing-Machine-Brooke-Gladstone-Media/dp/0393342468"&gt;The Influencing Machine&lt;/a&gt;
recommended (?) by Scott McCloud&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.thersa.org/"&gt;www.thersa.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://scottmccloud.com/4-inventions/canvas/index.html"&gt;The Infinite Canvas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://emcarroll.com/comics/faceallred/01.html"&gt;His Face All Red&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://comic.naver.com/webtoon/detail.nhn?titleId=350217&amp;amp;no=31&amp;amp;weekday=tue"&gt;Bongcheon-Dong Ghost&lt;/a&gt;
Creepy-ass Korean horror comic&lt;/li&gt;
&lt;li&gt;&lt;a href="http://imgur.com/gallery/uBYbJ"&gt;Bloom Like an Artist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/Weathercraft-Frank-Comic-Jim-Woodring/dp/1606993402"&gt;Weathercraft: A Frank Comic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Keynote by Jonathan Corum&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When we tell stories we adjust them based on audience - can&amp;#39;t do
that with a graphic&lt;/li&gt;
&lt;li&gt;Have an audience

&lt;ul&gt;
&lt;li&gt;He partitions his audience into reader viewer listener user&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Focus on the people rather than the mechanism/content delivery vehicle&lt;/li&gt;
&lt;li&gt;A colleague think s of designing for bart simpsons vs lisa simpsons

&lt;ul&gt;
&lt;li&gt;quick overview (Bart) vs ability to deep dive (Lisa)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;three types of people (science graphics)

&lt;ul&gt;
&lt;li&gt;high school science student&lt;/li&gt;
&lt;li&gt;busy commuter - how to keep them interested instead of going to
their phone, playing a game&lt;/li&gt;
&lt;li&gt;his grandmother - does it pull together as a cohesive visual whole?&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;whole goal is to design for someone else&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tensions

&lt;ul&gt;
&lt;li&gt;oversimplification vs. overwhelming detail&lt;/li&gt;
&lt;li&gt;explanation vs. decoration&lt;/li&gt;
&lt;li&gt;storytelling vs interactivity - narrative vs exploration&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;don&amp;#39;t be your own audience&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;show ideas + evidence&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;understand, translate, display, explain&lt;/li&gt;
&lt;li&gt;find the central idea. find one idea to use as the basis for your graphic&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;respect the reader - help them through the story&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;allow for multiple entry points - compartmentalized graphical sections&lt;/li&gt;
&lt;li&gt;interactive tools to allow reader to pace themselves through&lt;/li&gt;
&lt;li&gt;use disparate scales to give context. Example, mixing
longjump distances with free-throw line&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;add meaningful annotations&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;close proximity between graphics and labels&lt;/li&gt;
&lt;li&gt;don&amp;#39;t make people go back and forth between graphics and labels&lt;/li&gt;
&lt;li&gt;another way to provide context&lt;/li&gt;
&lt;li&gt;example: annotate each step in a sequence. flea jumping &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;show change&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;motion&lt;/li&gt;
&lt;li&gt;show large scale, small scale what&amp;#39;s happening each step&lt;/li&gt;
&lt;li&gt;change in form is another kind of change&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;reduce complexity and opportunities for confusion&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;adding interface can be adding complexity&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;reduce tedium&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interact with data, not the interface&lt;/li&gt;
&lt;li&gt;strip out tedious activities - usability&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;visualization is not explanation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dont let technology drive&lt;/li&gt;
&lt;li&gt;add enough information beyond your visualization to explain a pattern in data&lt;/li&gt;
&lt;li&gt;or structure your visualization to reveal and explain patterns&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;reveal patterns&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;layer multiple data sets&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;respect the data&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;show what&amp;#39;s unique about it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;if your visualization can apply to something completely different, you
  might not be telling the unique story. detainees vs cups of tea    &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;edit - throw things away.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;throw as much away as possible but actually tell a story&lt;/li&gt;
&lt;li&gt;If you&amp;#39;re spending most of your time editing you know you&amp;#39;re on
the right track&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;apply common sense vigorously&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Showing is Not Explaining, Pat Hanrahan&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;trying to explain Euclid&amp;#39;s algorithm for Greatest Common Divisor

&lt;ul&gt;
&lt;li&gt;algorithm animation / explanation&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;problems with animation

&lt;ul&gt;
&lt;li&gt;motion is fleeting and transient&lt;/li&gt;
&lt;li&gt;cannot simultaneously attend to multiple animations&lt;/li&gt;
&lt;li&gt;... more&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Pat showed the animation of the algorithm, but it didn&amp;#39;t really
explain how the algorim worked&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had trouble thinking of what to note for this one, would greatly
appreciate contributions here.&lt;/p&gt;

&lt;h2&gt;Choosing the Right Visual Story, Cheryl Phillips&lt;/h2&gt;

&lt;p&gt;Side note: This seemed mostly aimed at journalists.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What&amp;#39;s the story?

&lt;ul&gt;
&lt;li&gt;data without a theme is just a bunch of data - not a story&lt;/li&gt;
&lt;li&gt;who what when where why how - oldies but goodies&lt;/li&gt;
&lt;li&gt;interview your data. think of it as the man on the street. keep
asking it questions&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;avoid &amp;quot;notebook dump&amp;quot;

&lt;ul&gt;
&lt;li&gt;don&amp;#39;t put every last detail in the story&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;use the nutgraf (theme) to help define a strong visualization&lt;/li&gt;
&lt;li&gt;data is more than numbers -- what little stories make up the larger whole which can be visualized?

&lt;ul&gt;
&lt;li&gt;example: methadone the politics of pain&lt;/li&gt;
&lt;li&gt;example: family tree of songlaw&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;29, Nigel Holmes&lt;/h2&gt;

&lt;p&gt;My sparse notes here don&amp;#39;t really do the talk justice, probably
because I was enthralled with the presentation. Especially Nigel
attempting the long jump - I doubt any of us will forget seeing that!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;29 is not interesting in itself, but interesting in context&lt;/li&gt;
&lt;li&gt;you understand something when you see it next to something you already something understand&lt;/li&gt;
&lt;li&gt;context is the key to understanding&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;The Art of Honest Theft: Evolution of a connected scatterplot, Hannah Fairfield&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How graphics influence each other&lt;/li&gt;
&lt;li&gt;if you move away from plotting time against the horizontal you can
reveal interesting trends&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See
  &lt;a href="http://www.nytimes.com/2010/05/02/business/02metrics.html"&gt;Driving Shifts Into Reverse&lt;/a&gt;
  and
  &lt;a href="http://www.nytimes.com/interactive/2012/09/17/science/driving-safety-in-fits-and-starts.html"&gt;Driving Safety, in Fits and Starts&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;what&amp;#39;s next?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one technique: associate ancillary content (animations) with scroll&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;so that extra information shows up in a way that it&amp;#39;s tied to what the
  reader is reading at that moment &lt;em&gt;(this idea shows up a lot during the conf)&lt;/em&gt;
* focusing on immersive content
* it&amp;#39;s important to carve out time, even just 10%, to play&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;The Why Axis, Bryan Connor&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;nick felt (?) was inspiration&lt;/li&gt;
&lt;li&gt;is a critic on the why axis, but doesn&amp;#39;t mean that in a negative way&lt;/li&gt;
&lt;li&gt;&amp;quot;the finished piece frequently acts as a seductive screen that
distracts us from the higher level of investigation&amp;quot;&lt;/li&gt;
&lt;li&gt;move past being psychics into being an investigator: as a critic,
move from guessing to asking&lt;/li&gt;
&lt;li&gt;once you know the objective of the visualization you&amp;#39;re able to
judge whether it succeeded or failed&lt;/li&gt;
&lt;li&gt;designers: provide retros. be accessible to critics&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Visual storytelling in the Age of Data, Robert Kosara&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;academics don&amp;#39;t get the idea of presenting data, communicating data. it&amp;#39;s just an afterthought&lt;/li&gt;
&lt;li&gt;argues that stylizing charts is quite useful. helps to tell the
story. emotional impact?

&lt;ul&gt;
&lt;li&gt;example: monstrous data by Nigel Holmes&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;there&amp;#39;s a danger to telling stories&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;can lead you down the wrong path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;example: driving an electric car in the parking lot until the battery
 runs down&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;story telling potential of charts&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;table class="comparison"&gt;
    &lt;tr&gt;
        &lt;th&gt;Story Depth&lt;/th&gt;
        &lt;th&gt;Tells a Story&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Facts&lt;/td&gt;
        &lt;td&gt;Narrative&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Information Scent&lt;/td&gt;
        &lt;td&gt;Focus&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Audience&lt;/td&gt;
        &lt;td&gt;Author&lt;/tr&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;ul&gt;
&lt;li&gt;storytelling affordances &lt;em&gt;(I love the idea of storytelling affordances)&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt;the form which lends itself to storytelling&lt;/li&gt;
&lt;li&gt;what are they?

&lt;ul&gt;
&lt;li&gt;reading direction, left to right&lt;/li&gt;
&lt;li&gt;in the famous napoleon chart, the area gets thinner&lt;/li&gt;
&lt;li&gt;follow along a line, like following a journey on a map
uses the driving safety in fits and starts article as example&lt;/li&gt;
&lt;li&gt;animations&lt;/li&gt;
&lt;li&gt;direction - the bush admin vs. obama admin us job loss bar chart
effective way of walking you through developments&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;narrative ties facts together

&lt;ul&gt;
&lt;li&gt;provides causality&lt;/li&gt;
&lt;li&gt;walks you through a story&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;facts - story depth&lt;/li&gt;
&lt;li&gt;focus - tells a story

&lt;ul&gt;
&lt;li&gt;kind of the natural enemy of more data&lt;/li&gt;
&lt;li&gt;you must be selective in presenting data for it to be a story&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;information scent - story depth

&lt;ul&gt;
&lt;li&gt;hints used to guide people, indicate that there&amp;#39;s more data.
example: the jobless rate for people like you&lt;/li&gt;
&lt;li&gt;present a lot of information, but focus only on one bit.
provide other data in a less visually prominent manner&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;author - tells a story&lt;/li&gt;
&lt;li&gt;audience - story depth&lt;/li&gt;
&lt;li&gt;&amp;quot;we&amp;#39;re at the cusp of something amazing and powerful that goes way
beyond what&amp;#39;s out there right now&amp;quot;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;comics and visual communication, scott mccloud&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;in a 10&amp;quot; cube box of air is information

&lt;ul&gt;
&lt;li&gt;wifi, cell, radio&lt;/li&gt;
&lt;li&gt;until there&amp;#39;s something to decode that air, it really is just empty&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;we both receive meaning and create it on the fly

&lt;ul&gt;
&lt;li&gt;the artist gives a hint of life, and the audience will meet them half way&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;cartoonists

&lt;ul&gt;
&lt;li&gt;simplification creating a kind of human calligraphy&lt;/li&gt;
&lt;li&gt;write with pictures&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;human calligraphy takes many forms

&lt;ul&gt;
&lt;li&gt;body language&lt;/li&gt;
&lt;li&gt;facial expressions&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;there are six primary emotional expressions

&lt;ul&gt;
&lt;li&gt;anger&lt;/li&gt;
&lt;li&gt;disgust&lt;/li&gt;
&lt;li&gt;happiness&lt;/li&gt;
&lt;li&gt;surprise&lt;/li&gt;
&lt;li&gt;sadness&lt;/li&gt;
&lt;li&gt;fear&lt;/li&gt;
&lt;li&gt;the six primary combine

&lt;ul&gt;
&lt;li&gt;anger + happiness = cruelty&lt;/li&gt;
&lt;li&gt;you can paint on the face the variety of emotions&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;the grimace project

&lt;ul&gt;
&lt;li&gt;apparently useful for kids on the autism spectrum&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;secret ingredient of the look of love is sadness&lt;/li&gt;
&lt;li&gt;all pictures are words&lt;/li&gt;
&lt;li&gt;all pictures speak&lt;/li&gt;
&lt;li&gt;all pictures have something to say&lt;/li&gt;
&lt;li&gt;something happens in lower grades - teach kids to write and to draw

&lt;ul&gt;
&lt;li&gt;at a certain point we teach kids words can be used for

&lt;ul&gt;
&lt;li&gt;lists&lt;/li&gt;
&lt;li&gt;poems&lt;/li&gt;
&lt;li&gt;express themselves&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;but pictures - we try not to be too specific&lt;/li&gt;
&lt;li&gt;this overlooks the fact that pictures have a multiplicity of uses

&lt;ul&gt;
&lt;li&gt;can transmit messages, emotions&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;as a result we have a society that divorces pictures from... specificity?

&lt;ul&gt;
&lt;li&gt;we have downstream pictures - advertising&lt;/li&gt;
&lt;li&gt;don&amp;#39;t have as much going upstream&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;comics are a way to send messages upstream - can go out to a mass audience but retain their subjectivity&lt;/li&gt;
&lt;li&gt;will eisner believed comics can teach

&lt;ul&gt;
&lt;li&gt;the influencing machine&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;tone is important

&lt;ul&gt;
&lt;li&gt;readiness.gov spawned great parodies&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;now people are empowered to combine words and pictures anyway they want to

&lt;ul&gt;
&lt;li&gt;example: historical event facebook pages&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;we need to be vigilant of cognitive load time

&lt;ul&gt;
&lt;li&gt;the speed at which individual parts load is the speed at which we can convey complex info&lt;/li&gt;
&lt;li&gt;the rsanimate series, www.thersa.org&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;synchronization of data/visuals with content

&lt;ul&gt;
&lt;li&gt;&amp;quot;i&amp;#39;m not going to even allow you to think about anything other than what I&amp;#39;m talking about right now&amp;quot;&lt;/li&gt;
&lt;li&gt;order of presentation matters&lt;/li&gt;
&lt;li&gt;&amp;quot;if I don&amp;#39;t need to think it, I don&amp;#39;t need to see it&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;the quicker the parts the richer the whole&amp;quot; cognitive load&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;form and content must never apologize for each other&amp;quot;&lt;/li&gt;
&lt;li&gt;the grammar of comics is putting one picture after another

&lt;ul&gt;
&lt;li&gt;creating a flow of time between images&lt;/li&gt;
&lt;li&gt;as we move through space we move through time&lt;/li&gt;
&lt;li&gt;any two images, we&amp;#39;ll find a story, we&amp;#39;ll find a narrative&lt;/li&gt;
&lt;li&gt;cartoonists are finding the poetry in the gaps between frames&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;as storytellers, you want your audience to lose themselves in the story

&lt;ul&gt;
&lt;li&gt;all narrative art forms are based on extremely simple principles&lt;/li&gt;
&lt;li&gt;in comics: space = time&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;each successive technology would appropriate the previous technology as its content&amp;quot;&lt;/li&gt;
&lt;li&gt;grumpy old man rant about form factor

&lt;ul&gt;
&lt;li&gt;we see the world as rectangles in landscape mode&lt;/li&gt;
&lt;li&gt;what possibilities open up when you consider the monitor to be a
window?&lt;/li&gt;
&lt;li&gt;lots of cool examples of comics taking advantage of the
possibilities inherent in browsers&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;responsive web design

&lt;ul&gt;
&lt;li&gt;separating content from presentation&lt;/li&gt;
&lt;li&gt;a noble impulse&lt;/li&gt;
&lt;li&gt;but at the same time there are art forms which are fixed. comics is one of them&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;the form matters!

&lt;ul&gt;
&lt;li&gt;in comics, the spatial relationship is part of the artistic intent&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;when you have violent shifts in the landscape, the only thing you can do is hold on to basic principles

&lt;ul&gt;
&lt;li&gt;in comics, people losing themselves in the story&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many thanks to the hosts for putting together a great conference. I&amp;#39;m
looking forward to next year&amp;#39;s!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2013-02-23:/programming/datomic-for-five-year-olds/</id>
    <title type="html">Datomic for Five Year Olds</title>
    <published>2013-02-23T14:23:00Z</published>
    <updated>2013-02-23T14:23:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/programming/datomic-for-five-year-olds/" />
    <content type="html">&lt;p&gt;If you&amp;#39;re interested in
&lt;a href="http://docs.datomic.com/tutorial.html"&gt;Datomic&lt;/a&gt;, you may have been
deterred from checking it out because you lack the enthusiasm
necessary to slog through
&lt;a href="http://www.infoq.com/search.action?queryString=datomic&amp;amp;searchOrder=relevance&amp;amp;search=datomic"&gt;3 keynotes, 8 interviews, and innumerable walls of text&lt;/a&gt;
in order to get a basic idea of what the hell it is and whether you
should use it.&lt;/p&gt;

&lt;p&gt;Well, good news! I&amp;#39;ve done all that for you! How could I resist your
winning smile, you charmer you? After you&amp;#39;re done with this article,
you will have a solid conceptual grasp of the three key ways that
Datomic is unique. You will also understand key Datomic terms. This
will make it much easier to actually get your hands dirty with Datomic
if you decide to investigate it further.&lt;/p&gt;

&lt;h2&gt;Overview of Datomic&amp;#39;s Three Righteous Pillars of Databasing&lt;/h2&gt;

&lt;p&gt;Datomic differs from existing solutions in its &lt;em&gt;information model&lt;/em&gt;,
its &lt;em&gt;architecture&lt;/em&gt; and its &lt;em&gt;programmability&lt;/em&gt;. Below is a quick
overview. We&amp;#39;ll cover each of these righteous pillars of databasing in
much more detail.&lt;/p&gt;

&lt;table class="comparison"&gt;
    &lt;tr&gt;
        &lt;th&gt;&lt;/th&gt;
        &lt;th&gt;Relational DB&lt;/th&gt;
        &lt;th&gt;Schemaless DB&lt;/th&gt;
        &lt;th&gt;Datomic&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Information Model&lt;/td&gt;
        &lt;td&gt;The unit of information is an entity in a relation and you
            alter it in place, forgetting previous values&lt;/td&gt;
        &lt;td&gt;The unit of information is a schemaless document and you
            update it in place, forgetting previous values&lt;/td&gt;
        &lt;td&gt;The unit of information is a fact comprised of an entity,
            attributes, values, and time. You accrete the assertion and
            retraction of facts instead of updating in place.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Architecture&lt;/td&gt;
        &lt;td&gt;Database is a monolithic system responsible for querying,
            ACID compliance, and storage&lt;/td&gt;
        &lt;td&gt;Same as RDBMS&lt;/td&gt;
        &lt;td&gt;Separate querying, transacting, and storage in such a way
            that you get ACID compliance, read scalability, and more
            power within the application using Datomic&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Programmability&lt;/td&gt;
        &lt;td&gt;Applications abstract SQL by performing string
            manipulation&lt;/td&gt;
        &lt;td&gt;Interact with proprietary data structures which are more
            programming-friendly than SQL but less powerful&lt;/td&gt;
        &lt;td&gt;Datalog, completely uses data structures and has as much
            power as SQL&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;h2&gt;First Righteous Pillar of Databasing: Information Model&lt;/h2&gt;

&lt;p&gt;A database&amp;#39;s information model is defined by its rules regarding the
way entities and attributes relate to each other &amp;mdash; for lack of a
better term, its schema system.&lt;/p&gt;

&lt;p&gt;Yea, the choice between a relational and schemaless database is
probably your primary concern in choosing a database because of its
influence on how you write and grow your programs. You&amp;#39;ll see that
Datomic&amp;#39;s schema system isn&amp;#39;t as rigid as the relational model but
affords more power than a schemaless database.&lt;/p&gt;

&lt;p&gt;Additionally, a database&amp;#39;s information model is defined by its
approach to time. Datomic&amp;#39;s approach to time is different from most,
if not all, existing databases.&lt;/p&gt;

&lt;p&gt;Below are the schema systems for relational dbs, schemaless dbs, and
datomic, followed by a comparison of the way the information models
handle time.&lt;/p&gt;

&lt;h3&gt;Relational Schemas&lt;/h3&gt;

&lt;p&gt;You&amp;#39;re probably already familiar with the
&lt;a href="http://en.wikipedia.org/wiki/Relational_model"&gt;relational model&lt;/a&gt;.
Here are key definitions:&lt;/p&gt;

&lt;table&gt;
    &lt;tr&gt;
        &lt;td&gt;Entity&lt;/td&gt;
        &lt;td&gt;An entity is &lt;em&gt;tuple&lt;/em&gt; within a &lt;em&gt;relation&lt;/em&gt;. It
        is comprised of a fixed set of attributes. In practice, an
        entity is a row in a table.
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Attribute&lt;/td&gt;
        &lt;td&gt;A name + a data type. A column in a table. Attributes do not
        exist outside of relations. Attributes in different relations
        are always logically distinct, even if they hold the same
        type of data.&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;&lt;img src="/assets/images/posts/datomic/relational.png" alt="Relational"&gt;&lt;/p&gt;

&lt;p&gt;Probably the most important fact about the relational model is that
it&amp;#39;s rigid. Every entity must belong to a rigid relation. There&amp;#39;s no
way to add or remove attributes except by altering the structure of
the relation, which in turn alters every other entity in that relation.&lt;/p&gt;

&lt;h3&gt;Schemaless&lt;/h3&gt;

&lt;p&gt;Schemaless (NoSQL) databases were created to address the rigidity of
relational databases. They offer a few facilities for organization -
for example, collections in MongoDB - but forego any structure for
entities. This lack of structure comes at a cost: it limits your query
power and forces data integrity concerns into your application.&lt;/p&gt;

&lt;table&gt;
    &lt;tr&gt;
        &lt;td&gt;Entity&lt;/td&gt;
        &lt;td&gt;For our purposes, a document. A document has no
        restrictions on what attributes it can have.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Attribute&lt;/td&gt;
        &lt;td&gt;A name. Attributes can hold values of any type, and an attribute
        belonging to one entity is logically distinct from all other
        attributes, even those belonging to other entities within the same
        collection. Relationships between attributes are enforced
        within the client application.&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;&lt;img src="/assets/images/posts/datomic/schemaless.png" alt="Schemaless"&gt;&lt;/p&gt;

&lt;h3&gt;Datomic Schemas&lt;/h3&gt;

&lt;p&gt;In Datomic, a schema defines a core set of attributes which
effectively act as data types. An entity can possess any attribute
without restriction. In this way, entities have more structure than a
schemaless database but are more flexible than in relational
databases. Additionally, you retain the query power of the
relational model without having to handle data integrity concerns in
your client applications.&lt;/p&gt;

&lt;table&gt;
    &lt;tr&gt;
        &lt;td&gt;Entity&lt;/td&gt;
        &lt;td&gt;A map of attribute/value pairs. Entities have no fixed
        shape; they can be comprised of any attributes defined in the
        schema. &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Attribute&lt;/td&gt;
        &lt;td&gt;Name + data type + cardinality. Attributes themselves can
        be thought of as data types. They differ from attributes in
        the relational model in that they exist independently of rigid tables&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
        

&lt;p&gt;&lt;img src="/assets/images/posts/datomic/datomic.png" alt="Datomic"&gt;&lt;/p&gt;

&lt;h3&gt;Time&lt;/h3&gt;

&lt;p&gt;Datomic&amp;#39;s notion of time might be unfamiliar for those unacquainted
with Rich Hickey&amp;#39;s thoughts on time and how it relates to identity,
value, and state. To get up to speed, check out my article,
&lt;a href="/programming/the-unofficial-guide-to-rich-hickeys-brain/"&gt;&amp;quot;The Unofficial Guide to Rich Hickey&amp;#39;s Brain&amp;quot;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In both relational and schemaless databases, there&amp;#39;s no built-in
notion of time. It&amp;#39;s always &amp;quot;now&amp;quot; - the database doesn&amp;#39;t hold on to
the past. Whenever you update or delete a row, you have no way of
retrieving previous states for that row.&lt;/p&gt;

&lt;p&gt;This is the source of many headaches for us. If you&amp;#39;ve ever used or
any code that requires multiple trips to the database in order to
perform one unit of work, you know what I mean. In between each trip,
you have no way of knowing whether the database has been been altered.
You can end up writing all kinds of hacks to avoid race conditions and
still not end up with a bulletproof system.&lt;/p&gt;

&lt;p&gt;In addition, it&amp;#39;s virtually impossible to query past states. You might
not think this is really matters because you&amp;#39;re used to the
limitation, but being able to easily query past states is very
powerful.&lt;/p&gt;

&lt;p&gt;In Datomic, time is a first-class concept. All changes to the database
are associated with a transaction, and each transaction has a
timestamp. Rather than updating an entity in place and &amp;quot;forgetting&amp;quot;
its previous state, datomic &amp;quot;accretes&amp;quot; states. In this way, you&amp;#39;re
able to retrieve all previous states for an entity.&lt;/p&gt;

&lt;p&gt;&lt;img src="/assets/images/posts/datomic/time.png" alt="Datomic"&gt;&lt;/p&gt;

&lt;p&gt;Another way of thinking about it is that the database is an identity
which we superimpose on a time-ordered collection of values. In this
line of thinking, a &amp;quot;value&amp;quot; is the database as whole - its collection
of entities and attributes. When you run a transaction which creates,
updates, or deletes entities, you create a new database value. You&amp;#39;re
always able to say, &amp;quot;I want to work with the value of the database at
this point in time.&amp;quot;&lt;/p&gt;

&lt;h3&gt;Datomic&amp;#39;s Information Model Summarized&lt;/h3&gt;

&lt;p&gt;In Datomic, the unit of information is a fact. A fact is comprised of
an entity, an attribute, a value, and time. If you were to say &amp;quot;The
princess&amp;quot;, that would not be a fact. If you were to say, &amp;quot;The
princess&amp;#39;s favorite condiment&amp;quot;, that would not be a fact. A fact would
be &amp;quot;The princess&amp;#39;s favorite condiment is mustard,&amp;quot; that would be very
close to a fact. &amp;quot;The princess&amp;#39;s favorite condiment is mustard as of
10pm on February 10th.&amp;quot; is a fact.&lt;/p&gt;

&lt;p&gt;Facts don&amp;#39;t go away. If the princess&amp;#39;s tastes change so that she
prefers sriracha, it&amp;#39;s still useful to know that in the past she
preferred mustard. More importantly, new facts don&amp;#39;t obliterate old
facts. In Datomic, all prior facts are available. Also, in Datomic,
facts are called &amp;quot;datoms&amp;quot; and not &amp;quot;facts&amp;quot; because it&amp;#39;s more exciting
that way.&lt;/p&gt;

&lt;p&gt;For more, check out
&lt;a href="http://www.infoq.com/articles/Datomic-Information-Model"&gt;The Datomic Information Model&lt;/a&gt;,
an article by Datomic&amp;#39;s creator, Rich Hickey.&lt;/p&gt;

&lt;h2&gt;Second Righteous Pillar of Databasing: Architecture&lt;/h2&gt;

&lt;p&gt;Existing databases couple the following into one monolithic product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reading&lt;/li&gt;
&lt;li&gt;Writing&lt;/li&gt;
&lt;li&gt;Storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Datomic decouples these capabilities. All writing is handled by a
single &amp;quot;transactor&amp;quot;, ensuring ACID compliance. This is the only point
of similarity to existing solutions.&lt;/p&gt;

&lt;p&gt;Side note: the diagrams at the
&lt;a href="http://www.datomic.com/overview.html"&gt;Datomic Architectural Overview&lt;/a&gt;
page are quite awful. Besides being ugly, it is difficult to tell what
the visual components signify. What do the arrows mean? What does the
dashed border mean? WTF is &amp;quot;Comm&amp;quot;? Please, please fix these. OK, rant
over.&lt;/p&gt;

&lt;p&gt;Your application communicates with datomic through the Peer Library, a
component which exists within your applicaiton. Using the Peer Library
makes your application a Peer. I think the Datomic guys were trying to
avoid the term &amp;quot;client&amp;quot; here, but a Peer is essentially a client. What
makes a Peer diffeerent from the usual database client, however, is
that querying happens primarily in the Peer. By the way, when I say
&amp;quot;querying&amp;quot; I mean &amp;quot;read querying.&amp;quot;&lt;/p&gt;

&lt;p&gt;Instead of sending a query &amp;quot;over there&amp;quot; to the database server, which
runs the query and gives the client results, the Peer Library is
responsible for pulling the &amp;quot;value of the database&amp;quot; into the Peer so
that querying happens within your actual application. If you were to
create a script out of this action-packed drama, it would look like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Peer:&lt;/em&gt;&lt;/strong&gt; Peer Library! Find me all redheads who know how to play the
ukelele!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Peer Library:&lt;/em&gt;&lt;/strong&gt; Yes yes! Right away sir! Database - give me your
data!&lt;/li&gt;
&lt;li&gt;(Peer Library retrieves the database and performs query on it)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Peer Library:&lt;/em&gt;&lt;/strong&gt; Here are all ukelele-playing redheads!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Peer:&lt;/em&gt;&lt;/strong&gt; Hooraaaaaaaay!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most novel thing here is &amp;quot;retrieves the database&amp;quot;. In Datomic, you
have the concept of the &amp;quot;value of the database&amp;quot; - the database as a
whole, as a data structure. The Peer Library is responsible for
pulling as much of that data structure into memory as necessary to
satisfy your queries.&lt;/p&gt;

&lt;p&gt;In this way, your queries run largely in your application rather than
in a central database server, allowing for easy read scalability. It
gives more power to your application rather than keeping all the power
in a central server, where you have to worry about bottlenecks.&lt;/p&gt;

&lt;p&gt;Finally, Datomic does not implement its own storage solution but
instead relies on storage as a service, allowing you to choose which
storage backend you use. Right now, the following backends are
supported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The filesystem&lt;/li&gt;
&lt;li&gt;DynamoDB&lt;/li&gt;
&lt;li&gt;Riak&lt;/li&gt;
&lt;li&gt;Couchbase&lt;/li&gt;
&lt;li&gt;Infinispan&lt;/li&gt;
&lt;li&gt;SQL database&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Third Righteous Pillar of Databasing: Programmability&lt;/h2&gt;

&lt;p&gt;In Datomic, everything is data! Your schema is data! Queries are data!
Transactions are data! This is great because it&amp;#39;s easier to manipulate
data structures than it is to perform crazy string concatenation like
you do with SQL. Check out
&lt;a href="https://github.com/Datomic/day-of-datomic/blob/master/samples/seattle/getting-started.clj"&gt;these example queries&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.infoq.com/presentations/The-Design-of-Datomic"&gt;The Design of Datomic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.infoq.com/interviews/hickey-datomic"&gt;Rich Hickey on Datomic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.infoq.com/presentations/Value-Values"&gt;The Value of Values&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.infoq.com/articles/Datomic-Information-Model"&gt;The Datomic Information Model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.datomic.com"&gt;Datomic docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;The End&lt;/h2&gt;

&lt;p&gt;That&amp;#39;s it for now! If you have any suggestions or corrections please
let me know.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2012-12-06:/programming/the-unofficial-guide-to-rich-hickeys-brain/</id>
    <title type="html">The Unofficial Guide to Rich Hickey's Brain</title>
    <published>2012-12-06T05:00:00Z</published>
    <updated>2012-12-06T05:00:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/programming/the-unofficial-guide-to-rich-hickeys-brain/" />
    <content type="html">&lt;p&gt;&lt;img src="/assets/images/posts/rich-hickey-function.png" alt="The Rich Hickey Function"&gt;&lt;/p&gt;

&lt;p&gt;Part of my excitement in learning Clojure has been being exposed to
Rich Hickey&amp;#39;s thoughts on programming. Rich Hickey has a clear,
consistent way of viewing fundamental programming concepts that I
think any programmer would benefit from. Every time I watch one of his
talks, I feel like someone has gone in and organized my brain.&lt;/p&gt;

&lt;p&gt;In this article (and more to come (possibly)), I begin my attempt to
catalog Mr. Hickey&amp;#39;s unique viewpoint. Eventually, I would like to
produce a concise summary of his ideas. My hope is that this will
provide an easily-scannable reference to Clojurists and an accessible
introduction to non-Clojurists.&lt;/p&gt;

&lt;p&gt;What follows is derived from Rich Hickey&amp;#39;s talk,
&amp;quot;&lt;a href="http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey"&gt;Are we there yet?&lt;/a&gt;&amp;quot;&lt;/p&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Today&amp;#39;s OOP languages - Ruby, Java, Python, etc. - are fundamentally
flawed. They introduce
&lt;a href="http://en.wikipedia.org/wiki/No_Silver_Bullet"&gt;accidental complexity&lt;/a&gt;
by building on an inaccurate model of reality. Where they have
explicit definitions for the following concepts, the definitions are
wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Value&lt;/li&gt;
&lt;li&gt;State&lt;/li&gt;
&lt;li&gt;Identity&lt;/li&gt;
&lt;li&gt;Time&lt;/li&gt;
&lt;li&gt;Behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below, we&amp;#39;ll contrast the OOP viewpoint on each of these topics with
the Functional Programming viewpoint. But first, we&amp;#39;ll compare the
models of reality which underly OOP and FP. It&amp;#39;s this underlying
difference which gives rise to their different approach to the topics
above.&lt;/p&gt;

&lt;h2&gt;Metaphysics, Programming, and You: Comparing OOP and FP&lt;/h2&gt;

&lt;p&gt;When talking about metaphysics things tend to get a little fuzzy, but
hopefully this will all make sense.&lt;/p&gt;

&lt;p&gt;As the ever-trusty
&lt;a href="http://en.wikipedia.org/wiki/Metaphysics"&gt;Wikipedia&lt;/a&gt; explains,
metaphysics attempts to answer two basic questions in the broadest
possible terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is there?&lt;/li&gt;
&lt;li&gt;What is it like?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rich Hickey explains the difference between OOP and FP metaphysics by
contrasting their definitions of what a river is. &lt;/p&gt;

&lt;h3&gt;Object Oriented Programming&lt;/h3&gt;

&lt;p&gt;In OOP metaphysics, a river is something which actually exists in the
world. I know, I know, I can hear what you&amp;#39;re saying: &amp;quot;Uh... yeah?
So?&amp;quot; But believe me, the accuracy of that statement has caused many a
sleepless night for philosophers.&lt;/p&gt;

&lt;p&gt;The wrinkle is that the river is always changing. Its water never
ceases to flow. In OOP terms, we would say that it has mutable state,
and that its state is ever fluctuating.&lt;/p&gt;

&lt;p&gt;The fact that the state of the River Object and that Objects in
general are never stable doesn&amp;#39;t stop us from nevertheless treating
them as the fundamental building blocks of programs. In fact, this is
seen as an advantage of OOP - it doesn&amp;#39;t matter how the state changes,
you can still interact with a stable interface and all will work as it
should. An object can change, but to all observers it is still
considered the same object.&lt;/p&gt;

&lt;p&gt;This conforms to our intuitive sense of the world. The positions of
the electrons of the coffee in my mug matters naught; the coffee still
interacts with my taste buds in the way I expect.&lt;/p&gt;

&lt;p&gt;Finally, in OOP, objects do things. They act on each other. Again, this
conforms to our intuitive sense of the world where change is the
result of objects acting upon each other. A Person object pushes on a
Door object and enters a House object.&lt;/p&gt;

&lt;h3&gt;Functional Programming&lt;/h3&gt;

&lt;p&gt;&lt;img src="/assets/images/posts/fp-metaphysics.png" alt="FP Metaphysics"&gt;&lt;/p&gt;

&lt;p&gt;In FP metaphysics, we would say that we never step in the same river
twice. What we see as a discrete &lt;em&gt;thing&lt;/em&gt; which actually exists in the
world independent of its mutations is in reality a succession of
discrete, unchanging things.&lt;/p&gt;

&lt;p&gt;The &amp;quot;river&amp;quot; is not a thing in and of itself; it&amp;#39;s a concept
that we superimpose on a succession of related phenomena. This concept
is very useful - I won&amp;#39;t belabor that point - but it is just a
concept.&lt;/p&gt;

&lt;p&gt;What really exists are atoms (in the sense of atomic, unchanging,
stable entities) and processes. The river is not a stable object;
rather, it is a succession of related atoms which are generated by
some kind of process.&lt;/p&gt;

&lt;p&gt;These atoms don&amp;#39;t act upon each other and they can&amp;#39;t be changed. They
can&amp;#39;t &lt;em&gt;do&lt;/em&gt; anything. Change is not the result of one object acting on
another; change is the result of a process being applied to an
unchangeable atom. To say that something has changed is to say, &amp;quot;Oh,
there&amp;#39;s a new atom in this stream of atoms.&amp;quot; It&amp;#39;s like saying that
HEAD points to a new commit in your git repo.&lt;/p&gt;

&lt;p&gt;OK! Enough with metaphysics. Now let&amp;#39;s describe the more immediately
useful topics, starting with Value.&lt;/p&gt;

&lt;h2&gt;Value&lt;/h2&gt;

&lt;p&gt;It&amp;#39;s obvious that numbers like 3 and 6 and 42 are values. Numbers are
stable, unchanging.&lt;/p&gt;

&lt;p&gt;It should also be obvious that OO languages have &amp;quot;no proper notion&amp;quot; of
values in this sense. As Rich Hickey points out, you can create a
class whose instances are composed of immutable components, but there
is no high-level concept of immutable value implemented as a first
class construct within the class.&lt;/p&gt;

&lt;p&gt;This is one of the main causes of headaches when doing OOP. How many
times have you pulled your hair out trying to figure out how an
object&amp;#39;s attribute got changed? The fact is, in OO languages there is
no built in mechanism to ensure that the object you&amp;#39;re dealing with is
stable.&lt;/p&gt;

&lt;p&gt;This is the big reason why concurrent programming is so difficult.
Even in single-threaded programs this is a problem, and it&amp;#39;s one of
the reasons why we develop sprawling test suites. You can&amp;#39;t be sure if
a method call on your Toupee object is somehow going to cause a change
in your HipsterGlasses object.&lt;/p&gt;

&lt;p&gt;By contrast, in FP languages emphasis is placed on working with
immutable values. Since these values can&amp;#39;t change, a whole class of
problems simply disappears.&lt;/p&gt;

&lt;h2&gt;Identity&lt;/h2&gt;

&lt;p&gt;In the video, Mr. Hickey says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The biggest problem we have is we&amp;#39;ve conflated two things. We&amp;#39;ve
said the &lt;em&gt;idea&lt;/em&gt; that I attach to this thing that lasts over time
&lt;em&gt;is&lt;/em&gt; the thing that lasts over time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In FP, identity is essentially a name we give to a sequence of related
atoms. &amp;quot;River&amp;quot; refers to the sequence R1, R2, R3, etc, produced by the
river process. This is directly analogous to HEAD in git - it&amp;#39;s just a
name which is used to refer to actual values. In OO, there really
isn&amp;#39;t such a distinction.&lt;/p&gt;

&lt;p&gt;Or as the man himself says, &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Identity is a putative entity we associate with a series of causally
related values (states) over time. It&amp;#39;s a label, a construct we use
to collect a time series.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;State&lt;/h2&gt;

&lt;p&gt;In OO, there is no real clear definition of state. Maybe it&amp;#39;s, &amp;quot;the
values of all the attributes within an object right now.&amp;quot; And it has
to be &amp;quot;right now&amp;quot;, because there&amp;#39;s no language-supported way of
holding on to the past.&lt;/p&gt;

&lt;p&gt;This becomes clearer if you contrast it with the notion of identity in
FP. In the Hickeysian universe, a State is a specific value for an
identity at a point in time. (For me, this definition really clarified
my own thoughts.)&lt;/p&gt;

&lt;h2&gt;Time&lt;/h2&gt;

&lt;p&gt;There&amp;#39;s no real notion of time in OO. Everything&amp;#39;s just &amp;quot;right now&amp;quot;.
This is part of what causes problems in concurrent programs.&lt;/p&gt;

&lt;p&gt;By contrast, in the FP worldview we&amp;#39;ve been exploring, time is
well-defined. Time is a by-product of ordering states within an
identity.&lt;/p&gt;

&lt;p&gt;(By the way, I&amp;#39;d really like to write more here, and would appreciate
any suggestions.)&lt;/p&gt;

&lt;h2&gt;Behavior&lt;/h2&gt;

&lt;p&gt;Finally, behavior. I don&amp;#39;t have too much to write here - I might need
to watch some more talks - but I&amp;#39;ll include Mr. Hickey&amp;#39;s
thought-provoking observation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is no behavior. When you get hit by lightning, who&amp;#39;s behaving?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This may be what inspired Steve Yegge&amp;#39;s post,
&lt;a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html"&gt;Execution in the Kingdom of Nouns&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;The End&lt;/h2&gt;

&lt;p&gt;Well, that&amp;#39;s it for now. I hope you&amp;#39;ve found this post useful. If you
have any suggestions, I&amp;#39;d love to hear them!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2012-12-01:/penguins/my-failed-social-web-experiment/</id>
    <title type="html">My Failed(?) Social Web Experiment Still Haunts Me</title>
    <published>2012-12-01T05:00:00Z</published>
    <updated>2012-12-01T05:00:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/penguins/my-failed-social-web-experiment/" />
    <content type="html">&lt;p&gt;What will people post if they can&amp;#39;t include links and can&amp;#39;t use a
nickname?&lt;/p&gt;

&lt;p&gt;This was the question I was looking to answer back in 2007 I launched
nobodynotes.com. It was a very simple web site, consisting mainly of a
text field and all the posts which people had entered in the text
field. You can
&lt;a href="http://web.archive.org/web/20090402015728/http://nobodynotes.com/"&gt;see it, unstyled&lt;/a&gt;,
thanks to the wayback machine.&lt;/p&gt;

&lt;p&gt;Initially, the posts were interesting to me, but probably unremarkable
to anyone else. Bits of poetry, parts of song, random curses. But then
something unexpected happened. More and more of the posts were written
in Persian.&lt;/p&gt;

&lt;p&gt;Persian!? How did that happen? When I looked at Google Analytics, it
showed that the majority of my visits were from Iran, and that most of
my visitors were referred from Yahoo Mail. This was not something that
I had anticipated. It seemed like the site was going viral in Iran,
with people emailing it to each other specifically in Yahoo Mail.
Going through the site, I noticed that some of the posts referenced
others; each post had a number, and visitors would specify the number
of the post they were replying to. &lt;/p&gt;

&lt;p&gt;But why? Why all this activity from Iranians? I wanted to know, but
sadly had no direct way of finding out. After all, everyone was
anonymous. Not knowing what else, to do, I tried using Google
Translate to see what people were saying. One post in particular stood
out. It&amp;#39;s probably irretrievable now, but a young man essentially
wrote, &amp;quot;Help, I am a gay man living in Iran. I cannot tell anyone, or
I will be killed. Please, someone help me.&amp;quot;&lt;/p&gt;

&lt;p&gt;To this day, that post haunts me. Who was this young man? Was he able
to find help? Where is he today, and is he OK?&lt;/p&gt;

&lt;p&gt;I doubt I&amp;#39;ll ever know the answer. I eventually shut down the site as
traffic slowed to a trickle. But pieces of it remain. It was connected
to a &lt;a href="https://twitter.com/nobodynotes"&gt;twitter account&lt;/a&gt;, where you can
still read fragments of those posts by anonymous Iranians. And there&amp;#39;s
the wayback machine, which offers larger slices of conversation. And
there&amp;#39;s Google Translate, offering me its demented assistance in
trying to understand what was happening a world away:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Staring at the horizon, leaving the logo 
side of life, rectified love 
sitting in contemplation, madness, stood 
an innocent face, a tired face 
, relying on the fact, sad face smiling 
at what an idea! 
that madness pounding deep into each side. .&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2012-11-30:/programming/whoops-dci-refactoring/</id>
    <title type="html">A Detailed Look at a Small DCI Refactoring in Ruby</title>
    <published>2012-11-30T15:12:00Z</published>
    <updated>2012-11-30T15:12:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/programming/whoops-dci-refactoring/" />
    <content type="html">&lt;p&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;: this isn&amp;#8217;t actually &lt;span class="caps"&gt;DCI&lt;/span&gt;! Whoops!&lt;/p&gt;
&lt;p&gt;In this post I go over a small refactoring to clean up some code in &lt;a href="http://www.whoopsapp.com/"&gt;Whoops&lt;/a&gt; by implementing the &lt;span class="caps"&gt;DCI&lt;/span&gt; pattern. I&amp;#8217;ll cover the actual code changes and include my usual hand-wringing about what could be done better.&lt;/p&gt;
&lt;p&gt;This refactoring was inspired by Jim Gay&amp;#8217;s book &lt;a href="http://clean-ruby.com/"&gt;Clean Ruby&lt;/a&gt;. Jim Does an excellent job of concisely explaining what the &lt;span class="caps"&gt;DCI&lt;/span&gt; pattern (data, context, interaction) is, why it&amp;#8217;s useful, and how you can implement it in Ruby. This post isn&amp;#8217;t a review of Clean Ruby, but I will say that it&amp;#8217;s worth the money &amp;#8211; it&amp;#8217;s actually rekindled my enthusiasm for Ruby!&lt;/p&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;Whoops is a free, open-source Rails engine for logging. It&amp;#8217;s similar to Airbrake, Errbit, and &lt;a href="http://www.exceptional.io/"&gt;Exceptional&lt;/a&gt; except that it&amp;#8217;s not limited to exceptions &amp;#8211; you can log any event.&lt;/p&gt;
&lt;h2&gt;The Original Code and Its Defects&lt;/h2&gt;
&lt;p&gt;The code that got refactored is concerned with processing new events. You can see the entry point to this use case at lines 18-28 here:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/whoops-dci-refactoring/event.rb'&gt;whoops-dci-refactoring/event.rb&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Whoops&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Event&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;FieldNames&lt;/span&gt;
  
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:event_group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:class_name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Whoops::EventGroup&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:index&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
  
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:details&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:keywords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;DateTime&lt;/span&gt;

  &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="ss"&gt;:event_group_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="no"&gt;Mongo&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ASCENDING&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:event_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Mongo&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DESCENDING&lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;validates_presence_of&lt;/span&gt; &lt;span class="ss"&gt;:message&lt;/span&gt;  
  
  &lt;span class="n"&gt;before_save&lt;/span&gt; &lt;span class="ss"&gt;:set_keywords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:sanitize_details&lt;/span&gt;
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;with_indifferent_access&lt;/span&gt;
    
    &lt;span class="n"&gt;event_group_params&lt;/span&gt;                    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="no"&gt;Whoops&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;EventGroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;event_group_params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:last_recorded_at&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:event_time&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;event_group_params&lt;/span&gt;
    &lt;span class="n"&gt;event_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Whoops&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;EventGroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle_new_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_group_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    
    &lt;span class="n"&gt;event_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="no"&gt;Whoops&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;event_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt; 
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;conditions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Whoops&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;MongoidSearchParser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conditions&lt;/span&gt;
    &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conditions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_keywords&lt;/span&gt;
    &lt;span class="n"&gt;keywords_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;keywords_array&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;
    &lt;span class="n"&gt;add_details_to_keywords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keywords_array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keywords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keywords_array&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sanitize_details&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_a?&lt;/span&gt; &lt;span class="no"&gt;Hash&lt;/span&gt;
      &lt;span class="n"&gt;sanitized_details&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
      &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/\./&lt;/span&gt;
          &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\./&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_a?&lt;/span&gt; &lt;span class="no"&gt;Hash&lt;/span&gt;
          &lt;span class="n"&gt;child_keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;all_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;child_keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;any?&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;child_key&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;child_key&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/\./&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
            &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt;
          &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        
        &lt;span class="n"&gt;sanitized_details&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      
      &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sanitized_details&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;all_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_a?&lt;/span&gt; &lt;span class="no"&gt;Hash&lt;/span&gt;
        &lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;
        &lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="n"&gt;all_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;keys&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
    
  &lt;span class="kp"&gt;private&lt;/span&gt;

  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_details_to_keywords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keywords_array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flattened&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatten&lt;/span&gt;
    &lt;span class="n"&gt;flattened&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;respond_to?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    
    &lt;span class="k"&gt;until&lt;/span&gt; &lt;span class="n"&gt;flattened&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;
      &lt;span class="n"&gt;non_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flattened&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;keywords_array&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keywords_array&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;non_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;flattened&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;non_hash&lt;/span&gt;
      
      &lt;span class="n"&gt;flattened&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect!&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatten&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatten!&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;The above &lt;code&gt;record&lt;/code&gt; method calls &lt;code&gt;handle_new_event&lt;/code&gt; in &lt;code&gt;Whoops::EventGroup&lt;/code&gt; (lines 21-41):&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/whoops-dci-refactoring/event_group.rb'&gt;whoops-dci-refactoring/event_group.rb&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Whoops&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;EventGroup&lt;/span&gt;
  &lt;span class="c1"&gt;# notifier responsible for creating identifier from notice details&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Mongoid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;FieldNames&lt;/span&gt;
  
  &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="ss"&gt;:service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:event_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:event_group_identifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:logging_strategy_name&lt;/span&gt;
  &lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;string_field&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="n"&gt;string_field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:last_recorded_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;DateTime&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:archived&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:default&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:event_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:default&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_new_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;identifying_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="no"&gt;Whoops&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;EventGroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifying_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;event_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Whoops&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;EventGroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;identifying_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event_group&lt;/span&gt;
        &lt;span class="n"&gt;event_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;event_group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Whoops&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;EventGroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;valid?&lt;/span&gt;
        &lt;span class="n"&gt;event_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_notifications&lt;/span&gt;
        &lt;span class="n"&gt;event_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;archived&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
        &lt;span class="n"&gt;event_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;event_group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;event_group&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:class_name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Whoops::Event&amp;quot;&lt;/span&gt;
  
  &lt;span class="n"&gt;validates_presence_of&lt;/span&gt; &lt;span class="ss"&gt;:event_group_identifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:event_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:message&lt;/span&gt;
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;identifying_fields&lt;/span&gt;
    &lt;span class="n"&gt;field_names&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;last_recorded_at&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  
  &lt;span class="c1"&gt;# @return sorted set of all applicable namespaces&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;services&lt;/span&gt;
    &lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distinct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;should_send_notifications?&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;archived&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;new_record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;whoops_sender&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_notifications&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;should_send_notifications?&lt;/span&gt;
    &lt;span class="n"&gt;matcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Whoops&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;NotificationSubscription&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Matcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Whoops&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;NotificationMailer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_notification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;matching_emails&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deliver&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;matcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;matching_emails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;I&amp;#8217;ve included the full source of the files to show why this code doesn&amp;#8217;t belong. See, one of the main ideas in Jim&amp;#8217;s book is that code becomes unmaintainable when we start overburdening classes with methods that are only needed in specific contexts, or use cases. Additionally, we scatter all the code needed in one context across multiple classes and files rather than keeping it all in one place, creating a cognitive burden.&lt;/p&gt;
&lt;h3&gt;Violating The Single Responsibility Principle&lt;/h3&gt;
&lt;p&gt;In this case, the context is &amp;#8220;record an event.&amp;#8221; The code we&amp;#8217;ve added to the &lt;code&gt;Whoops::Event&lt;/code&gt; class begins to overburden the class by giving it a new responsibility and requiring that it &amp;#8220;know&amp;#8221; more about the outside world. Here&amp;#8217;s what the class is already responsible for, along with what we&amp;#8217;re adding:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;span class="caps"&gt;CRUD&lt;/span&gt; events&lt;/li&gt;
	&lt;li&gt;Massage event data before persistence&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;&lt;span class="caps"&gt;NEW&lt;/span&gt;&lt;/em&gt; Prepare event group data (lines 21-23)&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;&lt;span class="caps"&gt;NEW&lt;/span&gt;&lt;/em&gt; Initiate event group handling of new event (line 24)&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;&lt;span class="caps"&gt;NEW&lt;/span&gt;&lt;/em&gt; Figure out how to separate event-relevant data from event params (line 27)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this case, the impact isn&amp;#8217;t that high because we still don&amp;#8217;t even have 100 &lt;span class="caps"&gt;LOC&lt;/span&gt; for the entire class. But by continuing to shove code into a class just because a class&amp;#8217;s data or existing behavior is somehow involved, we transform our classes from usable, focused abstractions into code warehouses. And I really do mean warehouse. You have to start using signage in the form of comments or mixins to find your way around. &amp;#8220;Aaah yes, here we are, the email notification section!&amp;#8221; or &amp;#8220;Oh shit! it looks like someone put the methods for handling user registration at different ends of the file. Let&amp;#8217;s put those two guys together. There, what a tidy warehouse!&amp;#8221;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Whoops::EventGroup&lt;/code&gt; class was becoming a code warehouse. Here are the new responsibilities brought on by &lt;code&gt;handle_new_event&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;span class="caps"&gt;CRUD&lt;/span&gt; event groups&lt;/li&gt;
	&lt;li&gt;validate event groups&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;&lt;span class="caps"&gt;NEW&lt;/span&gt;&lt;/em&gt; send a notification on new events&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;&lt;span class="caps"&gt;NEW&lt;/span&gt;&lt;/em&gt; figure out whether a notification should be sent (lines 56-58)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This notification code is most definitely not the responsibility of a &lt;code&gt;Whoops::EventGroup&lt;/code&gt;. But here it is, because hey, fat model skinny controller.&lt;/p&gt;
&lt;h3&gt;Spreading Out Related Code&lt;/h3&gt;
&lt;p&gt;The above two files also show how related code gets spread out. In this case, to understand the full behavior of &amp;#8220;handle new event&amp;#8221; you have to start in the &lt;code&gt;Whoops::Event&lt;/code&gt; file, then go to the &lt;code&gt;Whoops::EventGroup&lt;/code&gt; file, then return back to the &lt;code&gt;Whoops::Event&lt;/code&gt; file.&lt;/p&gt;
&lt;h3&gt;Burdening Your Mind Grapes&lt;/h3&gt;
&lt;p&gt;(For more on mind grapes, see #6 in &lt;a href="http://www.cracked.com/article_15283_the-10-best-moments-from-3Cem3E30-rock3Cem3E.html"&gt;this cracked article&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;As anyone who&amp;#8217;s dealt with this kind of code can attest, organizing your code this way adds cognitive load. By violating the single responsibility principle, we make it more difficult for ourselves to find the methods we&amp;#8217;re interested in. The class&amp;#8217;s name starts to lose its meaning as its conceptual category becomes broader and broader until it becomes useless as an organizational unit. It&amp;#8217;s like trying to find the latest teen vampire romance novel at a bookstore only to find it in the computer section because the sexy, misunderstood male vampire love interest has an iphone.&lt;/p&gt;
&lt;p&gt;And everyone knows that having to navigate multiple files in order to understand one use case is a huge pain in the ass. I mean, that&amp;#8217;s pretty much why Chris Granger is making &lt;a href="http://www.lighttable.com/"&gt;Light Table&lt;/a&gt;, right?&lt;/p&gt;
&lt;h2&gt;The Refactoring&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/flyingmachine/whoops/compare/abc6d496024272e5a596d280bd47c51ba3a3d953...b6943881ddad094543d80528df79cc450e516c9f"&gt;This github diff&lt;/a&gt; shows all the changes to &lt;span class="caps"&gt;DCI&lt;/span&gt;-ify the code.&lt;/p&gt;
&lt;p&gt;As you can see, our &lt;code&gt;Whoops::Event&lt;/code&gt; and &lt;code&gt;Whoops::EventGroup&lt;/code&gt; classes are no longer violating the single responsibility principle. Now when you dig into those classes you no longer have to wade through code that&amp;#8217;s only tangentially related to the real purpose of those closses. We&amp;#8217;re no longer burdening our classes with knowledge that they shouldn&amp;#8217;t have, reducing coupling.&lt;/p&gt;
&lt;p&gt;Additionally, all of the code related to handling a new event is now in one place, the &lt;code&gt;Whoops::NewEvent&lt;/code&gt; class. This makes it much easier to understand completely everything that happens when a new event is handled. Rejoice!&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not sure how much more to say about the benefits of this refactoring. It feels a lot nicer to me, and it un-does the problems that existed earlier. Hopefully that&amp;#8217;s evident, but if it&amp;#8217;s not then please leave a comment or &lt;a href="http://twitter.com/nonrecursive"&gt;tweet me&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;The Promised Hand-Wringing&lt;/h2&gt;
&lt;p&gt;There are still some things that I&amp;#8217;m not completely happy with in &lt;code&gt;Whoops::NewEvent&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First, it basically looks one gigantic method that&amp;#8217;s been split up into tiny methods just so that I could name groups of related code. I don&amp;#8217;t know that there&amp;#8217;s much value in that.&lt;/p&gt;
&lt;p&gt;Second, lines 13-15 look like they need some sort of explanation. It&amp;#8217;s especially not obvious why I&amp;#8217;m setting archived to false.&lt;/p&gt;
&lt;p&gt;Last, I&amp;#8217;m not completely happy with the name NewEvent. If you were new to the project you&amp;#8217;d probably ask yourself, &amp;#8220;Uh&amp;#8230; how is that not Whoops::Event.new?&amp;#8221; I also considered &amp;#8220;Whoops::NewEventHandler&amp;#8221; but I was afraid that would summon Steve Yegge and he&amp;#8217;d make me read one of his 10,000 word essays.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d love to get some thoughts on this! Whether or not this is a reasonable &lt;span class="caps"&gt;DCI&lt;/span&gt; refactoring, I think that &lt;span class="caps"&gt;DCI&lt;/span&gt; is a great tool and something &lt;span class="caps"&gt;OOP&lt;/span&gt; folks should investigate.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2012-11-10:/programming/dissecting-gratefulplace/</id>
    <title type="html">Look, Ma! No batteries! A Clojure Web App Without Noir</title>
    <published>2012-11-10T18:23:00Z</published>
    <updated>2012-11-10T18:23:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/programming/dissecting-gratefulplace/" />
    <content type="html">&lt;p&gt;Awhile back I released &lt;a href="/programming/dissecting-omgsmackdown/"&gt;&lt;span class="caps"&gt;OMG&lt;/span&gt;! &lt;span class="caps"&gt;SMACKDOWN&lt;/span&gt;!!!&lt;/a&gt;, which still holds the title for dumbest Clojure app in existence. To make up for that ludicrostrosity, I&amp;#8217;ve created &lt;a href="http://gratefulplace.com"&gt;Grateful Place&lt;/a&gt;. This time I around I didn&amp;#8217;t use Noir, instead going closer to the metal with Compojure and Enlive. The experience was a lot easier than I anticipated, perhaps easier than using Noir. This post will cover some of the more interesting bits of code:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Templating heaven with Enlive and Middleman&lt;/li&gt;
	&lt;li&gt;Using macros to enforce full stack consistency&lt;/li&gt;
	&lt;li&gt;Roll-your-own validations&lt;/li&gt;
	&lt;li&gt;Pagination is more fun with macros&lt;/li&gt;
	&lt;li&gt;Using fierce mustaches to run tasks&lt;/li&gt;
	&lt;li&gt;Fun utilities&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find all source code on&lt;br /&gt;
&lt;a href="https://github.com/flyingmachine/gratefulplace/tree/v1.0.0"&gt;github&lt;/a&gt;. Also, I&amp;#8217;m going to be at the Clojure Conj and would love do meet folks. If you&amp;#8217;d like to chat, please do tweet me (@nonrecursive) or find me at the conj!&lt;/p&gt;
&lt;h2&gt;App Overview&lt;/h2&gt;
&lt;p&gt;Grateful Place is a social app with only a few models: Users, Comments, Posts, and Likes. Nothing too fancy. If you&amp;#8217;re interested in why I made it, here&amp;#8217;s a &lt;a href="/essays/gratitude/"&gt;post I wrote about gratitude&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Templating heaven with Enlive and Middleman&lt;/h2&gt;
&lt;h3&gt;Enlive is the bee&amp;#8217;s knees&lt;/h3&gt;
&lt;p&gt;I can say without reservation that &lt;a href="https://github.com/cgrand/enlive"&gt;Enlive&lt;/a&gt; is the best templating library I&amp;#8217;ve ever used. I absolutely love it! If you try out one thing from this post, try out the workflow I describe here. Enlive is completely different from Hiccup, &lt;span class="caps"&gt;ERB&lt;/span&gt;, &lt;span class="caps"&gt;HAML&lt;/span&gt; and the like and it&amp;#8217;s worth giving it a shot.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re not familiar with Enlive, it&amp;#8217;s a selector-based templating library. In the same way that &lt;span class="caps"&gt;CSS&lt;/span&gt; allows you to separate structure and presentation, Enlive lets you separate structure and view logic. This is huge! Unless you&amp;#8217;re the kind of person who still likes to use &lt;code&gt;font&lt;/code&gt; and &lt;code&gt;bold&lt;/code&gt; tags in your &lt;span class="caps"&gt;HTML&lt;/span&gt;, you should give Enlive a try.&lt;/p&gt;
&lt;h3&gt;Middleman/Enlive Workflow&lt;/h3&gt;
&lt;p&gt;Using Enlive allowed me to do all my design work using the Ruby library &lt;a href="http://middlemanapp.com/"&gt;Middleman&lt;/a&gt;. This allowed me to build stand-alone web pages so that I could see how they looked without worrying about any view logic. For example, here&amp;#8217;s the example home page I put together:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/assets/generator/source/index.html.haml'&gt;clojure/gratefulplace-dissected/v1/assets/generator/source/index.html.haml&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;
title: Grateful Place
&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;
&lt;span class="nf"&gt;#posts&lt;/span&gt;
  &lt;span class="nc"&gt;.post&lt;/span&gt;
    &lt;span class="nc"&gt;.content&lt;/span&gt;
      &lt;span class="nt"&gt;%p&lt;/span&gt; Here is some content.
    &lt;span class="nt"&gt;%footer&lt;/span&gt;
      &lt;span class="nc"&gt;.date&lt;/span&gt; Jan 03, 2012
      &lt;span class="nc"&gt;.author&lt;/span&gt;
        by
        &lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; Joe Schmoe
      &lt;span class="nc"&gt;.favorite&lt;/span&gt;
        &lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &amp;amp;#9733;
        &lt;span class="nc"&gt;.status&lt;/span&gt; Like this
      &lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="nc"&gt;.comments&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 35 Comments
      

  &lt;span class="nc"&gt;.post&lt;/span&gt;
    &lt;span class="nc"&gt;.content&lt;/span&gt;
      &lt;span class="nt"&gt;%p&lt;/span&gt; Here is some content, too.
    &lt;span class="nt"&gt;%footer&lt;/span&gt;
      &lt;span class="nc"&gt;.date&lt;/span&gt; Jan 03, 2012
      &lt;span class="nc"&gt;.author&lt;/span&gt;
        by
        &lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; Joe Schmoe
      &lt;span class="nc"&gt;.favorite&lt;/span&gt;
        &lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &amp;amp;#9733;
        &lt;span class="nc"&gt;.status&lt;/span&gt; Like this
      &lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="nc"&gt;.comments&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 35 Comments

  &lt;span class="nc"&gt;.pagination&lt;/span&gt;
    &lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="nc"&gt;.previous&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      Previous  
    &lt;span class="nt"&gt;%span&lt;/span&gt;&lt;span class="nc"&gt;.page-link.current&lt;/span&gt;
      1
    &lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="nc"&gt;.page-link&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      2
    &lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="nc"&gt;.page-link&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      3
    &lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="nc"&gt;.next&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;#&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      Next
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;You might have noticed a few weird things. First, this is written using &lt;span class="caps"&gt;HAML&lt;/span&gt;. Yep, &lt;span class="caps"&gt;HAML&lt;/span&gt;. I prefer &lt;span class="caps"&gt;HAML&lt;/span&gt; over &lt;span class="caps"&gt;HTML&lt;/span&gt; because it&amp;#8217;s more concise and the consistent structure allows me to visually scan it more easily. And since my &lt;span class="caps"&gt;HTML&lt;/span&gt; templates and view logic are completely separate, I can write my designs in &lt;span class="caps"&gt;HAML&lt;/span&gt;, preview them with Middleman, and then generate an &lt;span class="caps"&gt;HTML&lt;/span&gt; file for Enlive to work with. Here&amp;#8217;s my process in full:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Build on every change by cd&amp;#8217;ing to &lt;code&gt;assets/generator/&lt;/code&gt; and running &lt;code&gt;fswatch . ./g&lt;/code&gt;. This runs a bash script which generates the &lt;span class="caps"&gt;HTML&lt;/span&gt;, &lt;span class="caps"&gt;CSS&lt;/span&gt;, and Javascript files and moves them to the proper directories.&lt;/li&gt;
	&lt;li&gt;Start up Middleman by cd&amp;#8217;ing to &lt;code&gt;assets/generator/&lt;/code&gt; and running &lt;code&gt;middleman&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;View site at http://localhost:4567 and make changes to my heart&amp;#8217;s content&lt;/li&gt;
	&lt;li&gt;When I&amp;#8217;m happy with the changes, create or recompile a Clojure file which makes use of the &lt;span class="caps"&gt;HTML&lt;/span&gt; file with Enlive. It&amp;#8217;s necessary to recompile the files so that Enlive uses the updated &lt;span class="caps"&gt;HTML&lt;/span&gt;. That doesn&amp;#8217;t happen automatically.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Another thing you might have noticed is that in the &lt;span class="caps"&gt;HAML&lt;/span&gt; file I&amp;#8217;m showing two example posts. With Enlive, you actually have to add some logic to remove one of the post divs:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/views/posts.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/views/posts.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;39
40
41
42&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defpage&lt;/span&gt; &lt;span class="nv"&gt;all&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;index.html&amp;quot;&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;posts&lt;/span&gt; &lt;span class="nv"&gt;current-auth&lt;/span&gt; &lt;span class="nv"&gt;record-count&lt;/span&gt; &lt;span class="nv"&gt;page&lt;/span&gt; &lt;span class="nv"&gt;max-pages&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;;; don&amp;#39;t show the second post as it&amp;#39;s just an example&lt;/span&gt;
  &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="ss"&gt;:.post&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/nth-of-type&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)]]&lt;/span&gt; &lt;span class="nv"&gt;nil&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;h3&gt;Some code to reduce boilerplate&lt;/h3&gt;
&lt;p&gt;Finally, here&amp;#8217;s some code I put together to reduce boilerplate:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/views/common.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/views/common.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defonce &lt;/span&gt;&lt;span class="nv"&gt;template-dir&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;gratefulplace/templates/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/defsnippet&lt;/span&gt; &lt;span class="nv"&gt;nav&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str &lt;/span&gt;&lt;span class="nv"&gt;template-dir&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;index.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:nav&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;logged-in&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:.auth&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nv"&gt;logged-in&lt;/span&gt;
             &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/do-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/content&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Log Out&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/set-attr&lt;/span&gt; &lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/logout&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
             &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/do-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/content&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Log In&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/set-attr&lt;/span&gt; &lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/login&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/deftemplate&lt;/span&gt; &lt;span class="nv"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str &lt;/span&gt;&lt;span class="nv"&gt;template-dir&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;index.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;html&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:html&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/substitute&lt;/span&gt; &lt;span class="nv"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:nav&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/substitute&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;nav&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;current-authentication&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:nav&lt;/span&gt; &lt;span class="ss"&gt;:ul.secondary&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;logged-in&lt;/span&gt; &lt;span class="ss"&gt;:a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;if-let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;username&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:username&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;current-authentication&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/do-&amp;gt;&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/content&lt;/span&gt; &lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/set-attr&lt;/span&gt; &lt;span class="ss"&gt;:href&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/users/&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
  
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:nav&lt;/span&gt; &lt;span class="ss"&gt;:ul.secondary&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;logged-in&lt;/span&gt; &lt;span class="ss"&gt;:span&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;current-authentication&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/content&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Logged in as&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="c1"&gt;;; Need to come up with better name&lt;/span&gt;
&lt;span class="c1"&gt;;; Bundles together some defsnippet commonalities for user with the&lt;/span&gt;
&lt;span class="c1"&gt;;; layout template&lt;/span&gt;
&lt;span class="c1"&gt;;;&lt;/span&gt;
&lt;span class="c1"&gt;;; TODO destructuring doesn&amp;#39;t work in argnames&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defmacro &lt;/span&gt;&lt;span class="nv"&gt;defpage&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name &lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;argnames&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/defsnippet&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;symbol &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str name &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str &lt;/span&gt;&lt;span class="nv"&gt;template-dir&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:html&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;~@&lt;/span&gt;&lt;span class="nv"&gt;argnames&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="o"&gt;~@&lt;/span&gt;&lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;
       &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="ss"&gt;:keys&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;~@&lt;/span&gt;&lt;span class="nv"&gt;argnames&lt;/span&gt;&lt;span class="p"&gt;]}]&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;symbol &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str name &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;~@&lt;/span&gt;&lt;span class="nv"&gt;argnames&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;The ultimate purpose of this code is the &lt;code&gt;defpage&lt;/code&gt; macro. This helps me in a few ways. It lets me easily write view code for each page without having to worry about the surrounding layout. For example, before writing the above code I had to include the navigation transformations in every page, which quickly got annoying.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;defpage&lt;/code&gt; macro also bundles up the &lt;code&gt;template-dir&lt;/code&gt; variable, saving me some keystrokes and some duplication. Finally, it establishes a consistent way of interacting with the controller, a topic I&amp;#8217;ll explore more in the next section. Before that, here&amp;#8217;s an example of &lt;code&gt;defpage&lt;/code&gt; in action:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/views/posts.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/views/posts.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defpage&lt;/span&gt; &lt;span class="nv"&gt;show&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;posts/show.html&amp;quot;&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;post&lt;/span&gt; &lt;span class="nv"&gt;comments&lt;/span&gt; &lt;span class="nv"&gt;current-auth&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:.post&lt;/span&gt; &lt;span class="ss"&gt;:.author&lt;/span&gt; &lt;span class="ss"&gt;:a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;linked-username&lt;/span&gt; &lt;span class="nv"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:.post&lt;/span&gt; &lt;span class="ss"&gt;:.date&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/content&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;created-on&lt;/span&gt; &lt;span class="nv"&gt;post&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:.post&lt;/span&gt; &lt;span class="ss"&gt;:.content&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;md-content&lt;/span&gt; &lt;span class="nv"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:.post&lt;/span&gt; &lt;span class="ss"&gt;:.edit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;keep-when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;can-modify-record?&lt;/span&gt; &lt;span class="nv"&gt;post&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:.post&lt;/span&gt; &lt;span class="ss"&gt;:.edit&lt;/span&gt; &lt;span class="ss"&gt;:a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-path&lt;/span&gt; &lt;span class="nv"&gt;post&lt;/span&gt; &lt;span class="nv"&gt;post-edit-path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  

  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:.post&lt;/span&gt; &lt;span class="ss"&gt;:.moderate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;keep-when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;moderator?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:username&lt;/span&gt; &lt;span class="nv"&gt;current-auth&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:.post&lt;/span&gt; &lt;span class="ss"&gt;:.moderate&lt;/span&gt; &lt;span class="ss"&gt;:a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/do-&amp;gt;&lt;/span&gt;
                          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-path&lt;/span&gt; &lt;span class="nv"&gt;post&lt;/span&gt; &lt;span class="nv"&gt;post-path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/content&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:hidden&lt;/span&gt; &lt;span class="nv"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;unhide&amp;quot;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;hide&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
  
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h/set-attr&lt;/span&gt; &lt;span class="ss"&gt;:value&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt; &lt;span class="nv"&gt;post&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:.favorite&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;           &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;favorite&lt;/span&gt; &lt;span class="nv"&gt;current-auth&lt;/span&gt; &lt;span class="nv"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;Thanks to &lt;code&gt;defpage&lt;/code&gt;, my view code contains only logic specific to that view. I love it!&lt;/p&gt;
&lt;h2&gt;Using macros to enforce full-stack consistency&lt;/h2&gt;
&lt;h3&gt;Creating a route&amp;#8594;controller interface&lt;/h3&gt;
&lt;p&gt;When I was putting the app together, each of my compojure routes was a unique and beautiful snowflake:&lt;/p&gt;
&lt;pre class="emphasize"&gt;&lt;code class="emphasize"&gt;  (GET  "/users/new" []
        (users/show-new))&lt;/code&gt;
  
&lt;code class="emphasize"&gt;  (POST "/users" {params :params}
        (users/create! params))&lt;/code&gt;

&lt;code class="emphasize"&gt;  (GET  "/users/:username" [username]
        (users/show username))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, each route captures variables in a completely different way. At first I thought this made sense; I was passing exactly the data that was needed to each controller.&lt;/p&gt;
&lt;p&gt;However, this quickly became a pain in the ass. For example, if I wanted to make a request param available to a view, I had to modify functions all up and down the stack: in the routes, in the controller function, and in the view function. I ended up making all routes send the full request object to their functions:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/middleware/routes.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/middleware/routes.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defmacro &lt;/span&gt;&lt;span class="nv"&gt;route&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nb"&gt;path &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nb"&gt;path &lt;/span&gt;&lt;span class="nv"&gt;req#&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;req#&lt;/span&gt;
                &lt;span class="o"&gt;~@&lt;/span&gt;&lt;span class="nv"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt; &lt;span class="nv"&gt;routes&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;compojure.route/files&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:root&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;public&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;;; posts&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt; &lt;span class="nv"&gt;GET&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;posts/all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt; &lt;span class="nv"&gt;GET&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/posts&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;posts/all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt; &lt;span class="nv"&gt;GET&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/posts/new&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;posts/show-new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt; &lt;span class="nv"&gt;POST&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/posts&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;posts/create!&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;friend/authorize&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt; &lt;span class="nv"&gt;GET&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/posts/:id&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;posts/show&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt; &lt;span class="nv"&gt;GET&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/posts/:id/edit&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;posts/edit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt; &lt;span class="nv"&gt;POST&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/posts/:id&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;posts/update&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;route&lt;/code&gt; macro is very handy. It saves me from typing and (for the most part) from burning precious brain cells on thinking, and it enforces the &amp;#8220;send the full request&amp;#8221; constraint by not allowing me to deviate. Of course, I &lt;em&gt;can&lt;/em&gt; still deviate, and this is useful if you&amp;#8217;re using a library:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/middleware/routes.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/middleware/routes.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;56
57
58&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;friend/logout&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ANY&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/logout&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ring.util.response/redirect&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;If I want to get to the params, I just use a &lt;code&gt;let&lt;/code&gt;; no big deal:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/posts.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/posts.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;38
39
40&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;show&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;req&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-in&lt;/span&gt; &lt;span class="nv"&gt;req&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;h3&gt;Creating a controller&amp;#8594;view interface&lt;/h3&gt;
&lt;p&gt;In the same way that it was useful to create a route&amp;#8594;controller interface, it became useful to create a controller&amp;#8594;view interface. That was accomplished with this macro:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/common.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/common.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;55
56
57
58
59
60
61
62
63
64
65&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defmacro &lt;/span&gt;&lt;span class="nv"&gt;view&lt;/span&gt;
  &lt;span class="s"&gt;&amp;quot;provides defaults for the map provided to view functions and allows&lt;/span&gt;
&lt;span class="s"&gt;  you to provide additional key value pairs. Assumes that a variable&lt;/span&gt;
&lt;span class="s"&gt;  named req exists&amp;quot;&lt;/span&gt;

  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;view-fn&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x#&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:current-auth&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;friend/current-authentication&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="ss"&gt;:errors&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
             &lt;span class="ss"&gt;:params&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="ss"&gt;:req&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;req&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;view-fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;into &lt;/span&gt;&lt;span class="nv"&gt;x#&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map &lt;/span&gt;&lt;span class="nv"&gt;vec&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;partition&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;vec&lt;/span&gt; &lt;span class="nv"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)))))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;This also helped with one weird problem I ran into with cemerick&amp;#8217;s friend library where &lt;code&gt;(friend/current-authentication)&lt;/code&gt; returns nil from within an anonymous function (and there are many anonymous functions in my view code). I could circumvent this problem by assigning doing something like &lt;code&gt;(let [current-auth (friend/current-authentication)])&lt;/code&gt;. But it seemed to make more sense to just always pass that data along when calling view functions, as you can see in the macro above.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;defpage&lt;/code&gt; macro also helped in establishing this interface in that it allowed me to destructure the arguments sent by the controller. For example, if a controller had&lt;/p&gt;
&lt;pre class="emphasize"&gt;&lt;code class="emphasize"&gt;(view posts/show {:post post})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I could create the corresponding view with&lt;/p&gt;
&lt;pre class="emphasize"&gt;&lt;code class="emphasize"&gt;(defpage show [post current-authentication])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And I wouldn&amp;#8217;t even have to worry about the order of the arguments. It really reduced some &amp;#8220;incidental complexity&amp;#8221; (and I&amp;#8217;m almost certainly using that term incorrectly).&lt;/p&gt;
&lt;h2&gt;Roll-your-own validations&lt;/h2&gt;
&lt;p&gt;It wasn&amp;#8217;t too difficult to write my own way of doing validations, and I&amp;#8217;m satisfied with it for now. Here&amp;#8217;s a description of the data structure, with an example following:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Validation: a combination of a key and &amp;#8220;validation check groups&amp;#8221;&lt;/li&gt;
	&lt;li&gt;Validation check group: first element is an error message and the rest are &amp;#8220;validation checks&amp;#8221;. If any validation check returns false then the error message is added to a list of error messages for the given key.&lt;/li&gt;
	&lt;li&gt;Validation check: a boolean function to apply to one of a record&amp;#8217;s values. The value corresponds to the validation key&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#8217;s an example:&lt;/p&gt;
&lt;pre class="emphasize"&gt;&lt;code class="emphasize"&gt;(validate
 {:username "joebob", :password "hey"}
 {:password
   ["Your password must be at least 4 characters long"
    #(&amp;gt;= (count %) 4)]})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This validation would fail because the value &lt;code&gt;"hey"&lt;/code&gt; for the &lt;code&gt;:password&lt;/code&gt; is not at least four characters long. Here&amp;#8217;s the main validation code:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/common.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/common.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defmacro &lt;/span&gt;&lt;span class="nv"&gt;if-valid&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;to-validate&lt;/span&gt; &lt;span class="nv"&gt;validations&lt;/span&gt; &lt;span class="nv"&gt;errors-name&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;then-else&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;to-validate#&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;to-validate&lt;/span&gt;
         &lt;span class="nv"&gt;validations#&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;validations&lt;/span&gt;
         &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;errors-name&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt; &lt;span class="nv"&gt;to-validate#&lt;/span&gt; &lt;span class="nv"&gt;validations#&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;errors-name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;then-else&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;second &lt;/span&gt;&lt;span class="nv"&gt;then-else&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;error-messages-for&lt;/span&gt;
  &lt;span class="s"&gt;&amp;quot;return a vector of error messages or nil if no errors&lt;/span&gt;
&lt;span class="s"&gt;validation-check-groups is a seq of alternating messages and&lt;/span&gt;
&lt;span class="s"&gt;validation checks&amp;quot;&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="nv"&gt;validation-check-groups&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;
   &lt;span class="nv"&gt;identity&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;
    &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;when &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;not &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;last &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;partition&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="nv"&gt;validation-check-groups&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;validate&lt;/span&gt;
  &lt;span class="s"&gt;&amp;quot;returns a map of errors&amp;quot;&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;to-validate&lt;/span&gt; &lt;span class="nv"&gt;validations&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;validations&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;vec&lt;/span&gt; &lt;span class="nv"&gt;validations&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;loop &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="nv"&gt;v&lt;/span&gt; &lt;span class="nv"&gt;validations&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;if-let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;validation&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;fieldname&lt;/span&gt; &lt;span class="nv"&gt;validation-check-groups&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nv"&gt;validation&lt;/span&gt;
              &lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get &lt;/span&gt;&lt;span class="nv"&gt;to-validate&lt;/span&gt; &lt;span class="nv"&gt;fieldname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="nv"&gt;error-messages&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;error-messages-for&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="nv"&gt;validation-check-groups&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt; &lt;span class="nv"&gt;error-messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt; &lt;span class="nv"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;rest &lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recur&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;assoc &lt;/span&gt;&lt;span class="nv"&gt;errors&lt;/span&gt; &lt;span class="nv"&gt;fieldname&lt;/span&gt; &lt;span class="nv"&gt;error-messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;rest &lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
        &lt;span class="nv"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;if-valid&lt;/code&gt; wasn&amp;#8217;t strictly necessary but I made it and ended up liking it. It&amp;#8217;s a small improvement, but a handy one.&lt;/p&gt;
&lt;h2&gt;Pagination is more fun with macros&lt;/h2&gt;
&lt;p&gt;It was a bit difficult for me to pull the pagination code together. I tried many approaches, and I&amp;#8217;m not 100% satisfied with what I have, but it&amp;#8217;s better than nothing! The basic approach was to add a couple Korma clauses to a base set of clauses. Here are the base clauses, along with a macro that allows me to add more clauses willy-nilly:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/models/post.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/models/post.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;base&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;-&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;select*&lt;/span&gt; &lt;span class="nv"&gt;e/post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;e/user&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fields&lt;/span&gt; &lt;span class="ss"&gt;:username&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;e/comment&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;aggregate&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="ss"&gt;:*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:hidden&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;e/favorite&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;aggregate&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="ss"&gt;:*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt; &lt;span class="ss"&gt;:created_on&lt;/span&gt; &lt;span class="ss"&gt;:DESC&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defmacro &lt;/span&gt;&lt;span class="nv"&gt;all&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;clauses&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;base&lt;/span&gt;
       &lt;span class="o"&gt;~@&lt;/span&gt;&lt;span class="nv"&gt;clauses&lt;/span&gt;
       &lt;span class="nv"&gt;select&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;Here&amp;#8217;s the pagination macro:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/models/helpers.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/models/helpers.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;4
5
6
7
8
9&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;;; TODO make better!&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defmacro &lt;/span&gt;&lt;span class="nv"&gt;paginate&lt;/span&gt;
  &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;page&lt;/span&gt; &lt;span class="nv"&gt;num-per-page&lt;/span&gt; &lt;span class="nv"&gt;query&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
     &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~@&lt;/span&gt;&lt;span class="nv"&gt;query&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;num-per-page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dec &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;And here&amp;#8217;s the whole thing in action:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/posts.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/posts.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;all&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;req&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;current-auth&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;friend/current-authentication&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nv"&gt;per-page&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
        &lt;span class="nv"&gt;page&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str-&amp;gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;or &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-in&lt;/span&gt; &lt;span class="nv"&gt;req&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:params&lt;/span&gt; &lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="nv"&gt;conditions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;with-visibility&lt;/span&gt;
                     &lt;span class="nv"&gt;current-auth&lt;/span&gt;
                     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:moderator&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;
                      &lt;span class="ss"&gt;:logged-in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;or &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:hidden&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                                     &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:user_id&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;= &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt; &lt;span class="nv"&gt;current-auth&lt;/span&gt;&lt;span class="p"&gt;)]})&lt;/span&gt;
                      &lt;span class="ss"&gt;:not-logged-in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:hidden&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;
        &lt;span class="nv"&gt;record-count&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;post/record-count&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt; &lt;span class="nv"&gt;conditions&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;view&lt;/span&gt;
     &lt;span class="nv"&gt;view/all&lt;/span&gt;
     &lt;span class="ss"&gt;:posts&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;paginate&lt;/span&gt; &lt;span class="nv"&gt;page&lt;/span&gt; &lt;span class="nv"&gt;per-page&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;post/all&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt; &lt;span class="nv"&gt;conditions&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
     &lt;span class="ss"&gt;:record-count&lt;/span&gt; &lt;span class="nv"&gt;record-count&lt;/span&gt;
     &lt;span class="ss"&gt;:page&lt;/span&gt; &lt;span class="nv"&gt;page&lt;/span&gt;
     &lt;span class="ss"&gt;:max-pages&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;/ &lt;/span&gt;&lt;span class="nv"&gt;record-count&lt;/span&gt; &lt;span class="nv"&gt;per-page&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;I definitely think there&amp;#8217;s room for improvement here and would love suggestions.&lt;/p&gt;
&lt;h2&gt;Using fierce mustaches to run tasks&lt;/h2&gt;
&lt;p&gt;So it turns out that you can use leiningen to run tasks, kind of like Rake. As far as I know, it&amp;#8217;s not as powerful in that you can&amp;#8217;t specify dependencies, but it&amp;#8217;s still better than nothing! Here&amp;#8217;s a file I wrote to allow me to rebuild and re-seed by db:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/tasks/db.clj'&gt;clojure/gratefulplace-dissected/v1/src/tasks/db.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;ns &lt;/span&gt;&lt;span class="nv"&gt;tasks.db&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:refer-clojure&lt;/span&gt; &lt;span class="ss"&gt;:exclude&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;alter drop &lt;/span&gt;&lt;span class="nv"&gt;complement&lt;/span&gt;
                            &lt;span class="nv"&gt;bigint&lt;/span&gt; &lt;span class="nb"&gt;boolean char double float &lt;/span&gt;&lt;span class="nv"&gt;time&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;gratefulplace.models.user&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;lobos&lt;/span&gt; &lt;span class="nv"&gt;core&lt;/span&gt; &lt;span class="nv"&gt;connectivity&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;rebuild&lt;/span&gt;
  &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rollback&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;migrate&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;seed&lt;/span&gt;
  &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;user/create!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:username&lt;/span&gt;     &lt;span class="s"&gt;&amp;quot;higginbotham&amp;quot;&lt;/span&gt;
                          &lt;span class="ss"&gt;:email&lt;/span&gt;        &lt;span class="s"&gt;&amp;quot;daniel@flyingmachinestudios.com&amp;quot;&lt;/span&gt;
                          &lt;span class="ss"&gt;:display_name&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;higginbotham&amp;quot;&lt;/span&gt;
                          &lt;span class="ss"&gt;:password&lt;/span&gt;     &lt;span class="s"&gt;&amp;quot;password&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;-main&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;task-name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;condp&lt;/span&gt; &lt;span class="nb"&gt;= &lt;/span&gt;&lt;span class="nv"&gt;task-name&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;rebuild&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rebuild&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;seed&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;I ran &lt;code&gt;lein run -m tasks.db rebuild&lt;/code&gt; and &lt;code&gt;lein run -m tasks.db seed&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Fun utilities&lt;/h2&gt;
&lt;p&gt;Here&amp;#8217;s some stuff that was fun to write:&lt;/p&gt;
&lt;div class='attachment-path source'&gt;&lt;a href='/assets/source/clojure/gratefulplace-dissected/v1/src/gratefulplace/utils.clj'&gt;clojure/gratefulplace-dissected/v1/src/gratefulplace/utils.clj&lt;/a&gt;&lt;/div&gt;&lt;div class='code pygments'&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;ns &lt;/span&gt;&lt;span class="nv"&gt;gratefulplace.utils&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;str-&amp;gt;int&lt;/span&gt;
  &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Integer.&lt;/span&gt;  &lt;span class="nv"&gt;str&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="nv"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;if-let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;val &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;k&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;assoc &lt;/span&gt;&lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="nv"&gt;k&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str-&amp;gt;int&lt;/span&gt; &lt;span class="nv"&gt;val&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="nv"&gt;m&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="nv"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;deserialize&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;ks&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;assoc &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;%2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;read-string&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;%2&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="nv"&gt;ks&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defmacro &lt;/span&gt;&lt;span class="nv"&gt;self-unless-fn&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt; &lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;otherwise&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;self#&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="nv"&gt;self#&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;otherwise&lt;/span&gt;
       &lt;span class="nv"&gt;self#&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;h2&gt;The End&lt;/h2&gt;
&lt;p&gt;And that&amp;#8217;s it! I hope you&amp;#8217;ve found this useful. I&amp;#8217;d love any feedback, so please do leave a comment or tweet me or email me. And like I mentioned above &amp;#8211; it&amp;#8217;d be great to meet some folks at the Conj next week!&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2012-11-07:/essays/loving-without-fear/</id>
    <title type="html">Loving Without Fear</title>
    <published>2012-11-08T01:02:00Z</published>
    <updated>2012-11-08T01:02:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/essays/loving-without-fear/" />
    <content type="html">&lt;p&gt;I was sitting at the Cambridge Public Library, and for the first time
in months - years? - I felt at peace. In my journal I had just written
what&amp;#39;s become a kind of mantra for me: &amp;quot;Love without fear.&amp;quot;&lt;/p&gt;

&lt;p&gt;At the time I was going through a very difficult breakup. My
relationship of 6 years had been slowly and painfully dissolving, in
part because of my own inability to end it decisively.&lt;/p&gt;

&lt;p&gt;Part of my difficulty what was that I had a lot of guilt over wanting
to end the relationship because the person I was with had a long-term
illness and I was supporting her both financially and as a kind of
house helper or ersatz nurse. I had watched her suffer terribly.&lt;/p&gt;

&lt;p&gt;I&amp;#39;m not sure how to convey what that was like. How do you share the
experience of watching someone you love get a spinal tap? Of wheeling
them out of the hospital and to the hotel next door, trying to do it
quickly but smoothly because every bump causes excruciating pain? Or
how about cleaning the vomit out of a mixing bowl because antibiotics
are causing her nausea? Or giving the antibiotics shots yourself,
night after night? Or knowing that there was no end in sight? How
could I leave someone to face that on her own?&lt;/p&gt;

&lt;p&gt;After six years, I was in a state of chronic exhaustion and stress.
Often I would start my day by sitting at my desk for a couple hours
and just staring, not really able to do anything. I knew that
something had to change, but I felt too guilty to leave.&lt;/p&gt;

&lt;p&gt;And, to be completely honest, I was scared about what it might say
about me if I left her. Would it mean that I was a callous, heartless
person?  More, I was scared to live without her. We&amp;#39;d been together for
6 years, and the life I knew was familiar and provided comfort in a
way. In the state I was in, I did not feel confident that I could make
a large life change. Michael Singer said it well:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You will get to a point in your growth where you understand that if
you protect yourself, you will never be free. It’s that simple.
Because you’re scared, you have locked yourself within your house
and pulled down all the shades. Now it’s dark and you want to feel
the sunlight, but you can’t. It’s impossible. If you close and
protect yourself, you are locking this scared, insecure person
within your heart. You will never be free that way.&lt;/p&gt;

&lt;p&gt;-- The Untethered Soul, by Michael Singer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But those words, &amp;quot;love without fear&amp;quot;, helped give me strength. Beneath
the fear, beneath the raw ache of being a perpetual witness to
suffering, I could still feel the beating heart of love. I felt it
there, ready, waiting for me without judgment. I felt the desire to
open up again, to build honest and meaningful relationships with
others. I felt like I had nothing to fear from embracing every moment
of life whole-heartedly.&lt;/p&gt;

&lt;p&gt;The months that followed that day at the library were messy and
painful in many ways. But despite many mistakes, I knew that basically
I was on the right path, that my heart was opening up more and more
and I was learning to love myself and be myself without giving in to
my fears of what other people might think or what vague disaster might
befall me.&lt;/p&gt;

&lt;p&gt;Now, more than two and a half years later, I can say without
reservation that I took the right path. My life has not been
problem-free and I don&amp;#39;t ever expect it to be. In embracing love,
though, I&amp;#39;ve learned that freedom and joy can be found in every
moment, even when problems do arise.&lt;/p&gt;

&lt;p&gt;My life has improved as well. Actually, that&amp;#39;s a major understatement.
My life is freaking &lt;em&gt;awesome&lt;/em&gt; right now. About a month ago, I got
engaged to the girl I love. A few days ago, I moved out of a drafty,
gross old apartment into a beautiful new house that&amp;#39;s close enough to
my brother and mom to allow me to visit them much more often. And my
latest project, something I put together with the idea of lifting up
other people, is almost ready to ship.&lt;/p&gt;

&lt;p&gt;And through it all, I keep telling myself: &lt;em&gt;Love without fear. Love
without fear. Love without fear.&lt;/em&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2012-10-16:/essays/gratitude/</id>
    <title type="html">Daily Gratitude</title>
    <published>2012-10-17T01:02:00Z</published>
    <updated>2012-10-17T01:02:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/essays/gratitude/" />
    <content type="html">&lt;p&gt;Around the beginning of the year I read about the benefits of
cultivating a daily practice of gratitude. Making a point of being
grateful trains you to think more positively and just makes you feel
better.&lt;/p&gt;

&lt;p&gt;I&amp;#39;ve personally found it to be a rewarding, easy practice. Every
morning I think about three things that I&amp;#39;m grateful for as soon as I
wake up, and it&amp;#39;s a fantastic way to start the day. And over the past
six months, I&amp;#39;ve found myself feeling grateful for my life much more
often.&lt;/p&gt;

&lt;p&gt;The fact is, I have a great life. I do what I love, I&amp;#39;m with the woman
I love, and I&amp;#39;m financially secure. Now I appreciate my great
situation much more than I did six months ago.&lt;/p&gt;

&lt;p&gt;And if there&amp;#39;s something in my life I want to change, practicing
gratitude has helped to give me the energy to change it. Instead of
feeling overwhelmed and anxious, I feel like I ultimately have nothing
to worry about.&lt;/p&gt;

&lt;p&gt;The best part about it is that it&amp;#39;s freaking easy and only takes a few
minutes, but the benefits are huge and accumulate over time. It&amp;#39;s
such a powerful practice that I truly think everyone should try it.
Here are a couple suggestions for getting started:&lt;/p&gt;

&lt;h2&gt;What you don&amp;#39;t lack&lt;/h2&gt;

&lt;p&gt;It&amp;#39;s easy to take our everyday lives for granted. If you have a
toothache, you are grateful when it&amp;#39;s gone. But you quickly adjust to
your new situation and forget that your tooth is better.&lt;/p&gt;

&lt;p&gt;But when you look closely, you can see that our everyday lives are
full of small miracles like these. Do you have food? Do you have your
vision? Your hearing? None of these are guaranteed to anyone.&lt;/p&gt;

&lt;p&gt;As Thich Nhat Hanh put it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For me, to be alive is a miracle. It is the greatest of all
miracles. To feel that you are alive and are breathing in is to
perform a miracle - one that you can perform at any time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or think about this. There&amp;#39;s a condition called &amp;quot;alien hand syndrome&amp;quot;
where those who suffer from it can&amp;#39;t control one of their hands. They
try to button up their shirt with one hand, and the other hand
unbuttons it. They move in to hug a loved one, only to have the alien
hand punch the person. Not having alien hand syndrome is something to
be grateful for.&lt;/p&gt;

&lt;h2&gt;Your past&lt;/h2&gt;

&lt;p&gt;Is there anyone in your past that helped you when you needed it?&lt;/p&gt;

&lt;p&gt;Did you have good friends? A family that loved you?&lt;/p&gt;

&lt;p&gt;Even if you are feeling a lack in your life now, you can be grateful
for what you&amp;#39;ve had in the past. Even if it&amp;#39;s difficult, trying
feeling grateful for people or events in your past.&lt;/p&gt;

&lt;p&gt;These two sources - your past and what you don&amp;#39;t lack - can be very
fruitful sources of gratefulness.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2012-09-21:/essays/love-is-power/</id>
    <title type="html">Love is Power</title>
    <published>2012-09-21T15:55:00Z</published>
    <updated>2012-09-21T15:55:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/essays/love-is-power/" />
    <content type="html">&lt;p&gt;&amp;quot;You can&amp;#39;t park like that, you dumb bitch!&amp;quot; A man, not ten feet away,
had just shouted this at my then-girlfriend Su.&lt;/p&gt;

&lt;p&gt;It was the middle of winter in New England, and the streets were
narrow with large snow banks piled on each side. Earlier, Su had
called people all day trying to get someone to remove the snow -- to
no avail.&lt;/p&gt;

&lt;p&gt;That night I was helping her get groceries out of the car, parked
temporarily in front of the house, and the snow bank made it hard for
other cars to pass. She laughingly commented that &amp;quot;now people can&amp;#39;t
get through!&amp;quot; Besides being unable to finding someone to plow the
snow, a lot of other stuff had gone wrong that day, and the best we
could do was laugh.&lt;/p&gt;

&lt;p&gt;And then that man starting shouting at us from inside his truck. We
took it in stride, but then the guy rolled down his window. He just
wouldn&amp;#39;t stop. He parked up the street, got out and continued
shouting, even after we told him we were parked there because Su&amp;#39;s
disabled and that we&amp;#39;d call the police if he didn&amp;#39;t stop.&lt;/p&gt;

&lt;p&gt;When he finally left I was furious. This was right before heading to
aikido practice, so I thought to myself, &amp;quot;What&amp;#39;s an aikido way to deal
with this?&amp;quot; If you don&amp;#39;t know what aikido is, it&amp;#39;s pretty much a
martial art for hippies. Here&amp;#39;s a quote from its founder:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Aikido is love. You make this great great love of the universe your
heart and then you must make your own mission the protection and love
of all things.&lt;/p&gt;

&lt;p&gt;-- O&amp;#39;Sensei&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In aikido you train to extend love to all things - including angry
jerks yelling at you for no reason. Including people who are attacking
you, whether physically or verbally or indirectly.&lt;/p&gt;

&lt;p&gt;So I took a step back, and tried to see it from Angry Jerk&amp;#39;s
perspective. Clearly, he was distressed. For someone to blow up
uncontrollably like that they have to be in some kind of emotional
turmoil. And that freed something up inside me.&lt;/p&gt;

&lt;p&gt;Thinking about Angry Jerk with love and compassion opened up enough
space for me to realize that, actually, I was completely OK. Sure,
this guy had made me scared, but right then I was physically safe and
unharmed. What I found was that extending love and compassion
towards the people attacking you forces you to be OK. You have to be
full in order to give, and the act of giving creates fullness&lt;/p&gt;

&lt;p&gt;I went to AJ&amp;#39;s house. When I knocked on the door, he answered it, and
I said something like, &amp;quot;I know that the way we parked made it hard to
drive -- in fact, we were about to move the car when you came by.
We&amp;#39;re sorry it made it hard for you to drive.&amp;quot;&lt;/p&gt;

&lt;p&gt;We went back and forth a little, and the guy said he thought Su was
laughing at him. When I told him she was laughing at the situation,
not at him, he started saying he was sorry over and over, sorry for
being a jerk, and I should tell Su he apologized.&lt;/p&gt;

&lt;p&gt;In this situation, many people would feel like they had to &amp;quot;set this
jackass straight&amp;quot;. They&amp;#39;d feel the need to assert their manhood or
otherwise angrily retaliate to demand respect.&lt;/p&gt;

&lt;p&gt;But think about it - how likely are you to respect someone who&amp;#39;s
blowing up at you? Fear them, maybe. Respect them, no. Besides that,
you risk escalating the situation to the point where it does become
physical. And finally, you end up losing sight of the fact that
another human is in distress. You diminish your capacity for
compassion.&lt;/p&gt;

&lt;p&gt;We never invited the guy over for dinner or anything, but I think
the situation was resolved pretty happily. It was pretty awesome to be
able to confront the guy in a non-threatening, non-accusatory way, and
to have him end up apologizing.&lt;/p&gt;

&lt;p&gt;There have been many other times during my life where I&amp;#39;ve employed
this technique, and it has never failed me. It empowers me to protect
myself and in the process lift up others.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2012-09-09:/programming/foreman-released/</id>
    <title type="html">Releasing Foreman</title>
    <published>2012-09-09T23:55:00Z</published>
    <updated>2012-09-09T23:55:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/programming/foreman-released/" />
    <content type="html">&lt;p&gt;My first ever &lt;a href="/foreman"&gt;Mac app&lt;/a&gt; is out. Get it while it&amp;#39;s hot!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2012-08-27:/essays/learn-to-learn/</id>
    <title type="html">On Learning Skills (A Response to Move Your Feet)</title>
    <published>2012-08-27T16:23:00Z</published>
    <updated>2012-08-27T16:23:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/essays/learn-to-learn/" />
    <content type="html">&lt;p&gt;Matt Swanson wrote an inspiring
&lt;a href="http://swanson.github.com/blog/2012/08/27/move-your-feet.html"&gt;blog post&lt;/a&gt;
on learning new skills and developing new habits. Below is additional
information that could help you learn a new programming skill or
develop a new programming habit, along with additional resources.
Here&amp;#39;s the summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Programming is a skill

&lt;ul&gt;
&lt;li&gt;You need practice as well knowledge&lt;/li&gt;
&lt;li&gt;Learning can be seen as a process of bridging your gaps&lt;/li&gt;
&lt;li&gt;Performing a new skill requires you to develop new habits, and
the rules for forming habits apply&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;There are many things you can do to successfully create a new habit

&lt;ul&gt;
&lt;li&gt;Social support&lt;/li&gt;
&lt;li&gt;Environmental support&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Programming is a skill&lt;/h2&gt;

&lt;p&gt;Programming is a skill, which means that learning programming
languages and techniques is not as simple as accumulating facts.
No written guide to programming, no matter how thorough, will ever be
sufficient because there are countless details which have to be left
out, details which you can only assimilate while engaging in the
practice of programming.&lt;/p&gt;

&lt;p&gt;No one would suggest that you could become a world-class singer by
merely going through a book on the subject. With these physical
skills, it&amp;#39;s obvious that learning involves doing something other than
just absorbing knowledge. I think that, with programming, its nature
as a skill is often overlooked because it&amp;#39;s knowledge work. The key
thing to keep in mind is that you must actually do programming in
order to learn languages and techniques.&lt;/p&gt;

&lt;p&gt;In Matt&amp;#39;s case, he was also trying to develop a new habit - using TDD.
Many aspects of programming are like this. Perhaps you want to start
documenting your code more or you want to start doing daily standup
with your team or &lt;em&gt;whatever&lt;/em&gt;. These are all habits, some involving
just you and some involving your team or organization. Recognizing
them as habits will allow you to apply techniques for successfully
developing a new habit.&lt;/p&gt;

&lt;p&gt;One habit that you can start developing now is to identify your
learning gaps
(This list, by the way, is pulled in part from
&lt;a href="http://www.amazon.com/gp/product/0321768434/ref=as_li_ss_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0321768434&amp;amp;linkCode=as2&amp;amp;tag=aflyingmachin-20"&gt;Design for How People Learn&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Knowledge

&lt;ul&gt;
&lt;li&gt;What information do you need to be successful?&lt;/li&gt;
&lt;li&gt;Where kind you find this information?&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Skill

&lt;ul&gt;
&lt;li&gt;What will you need to practice to develop the desired
proficiency?&lt;/li&gt;
&lt;li&gt;How can you make opportunities for practice?&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Motivation

&lt;ul&gt;
&lt;li&gt;How do you actually feel about learning the skill?&lt;/li&gt;
&lt;li&gt;Do you feel resistant to changing?&lt;/li&gt;
&lt;li&gt;&lt;a href="/essays/how-to-get-and-stay-motivated/"&gt;More on motivation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Environment

&lt;ul&gt;
&lt;li&gt;Do you have all the tools you need?&lt;/li&gt;
&lt;li&gt;Are they within easy reach? For example - if you want to run
like Matt, are your shoes in your closet or right by your bed so
that you can put them on first thing in the morning?&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Programming is comprised of habits&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;I&amp;#39;m not a great programmer, I&amp;#39;m a pretty good programmer with great
habits&lt;/p&gt;

&lt;p&gt;-- Kent Beck&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There&amp;#39;s a mountain of text out there on how to form habits. Here&amp;#39;s my
contribution to that mountain!&lt;/p&gt;

&lt;h3&gt;Get Social Support&lt;/h3&gt;

&lt;p&gt;Enlist your coworkers. Go to hackfests. Changing your habits is way,
way easier when you have other people supporting you.&lt;/p&gt;

&lt;h3&gt;Environmental Support&lt;/h3&gt;

&lt;p&gt;Change your environment to make your new habit &lt;em&gt;easy&lt;/em&gt; to do and
antagonistic habits &lt;em&gt;hard&lt;/em&gt; to do. As I mentioned above - put your
running shoes by your bed.&lt;/p&gt;

&lt;p&gt;When it comes to programming - change your environment to support your
new habits. When I started learning Clojure, I invested a lot of
effort up front in making it painless to actually run Clojure code
because I knew that otherwise it would be too easy to just tell myself
&amp;quot;meh, I&amp;#39;ll get to this later. Now, time to learn angular.js!&amp;quot; or
something like that.&lt;/p&gt;

&lt;h3&gt;Develop Motivation&lt;/h3&gt;

&lt;p&gt;I have a &lt;a href="/essays/how-to-get-and-stay-motivated/"&gt;little essay&lt;/a&gt; on
this topic.&lt;/p&gt;

&lt;p&gt;Finally,
&lt;a href="http://www.amazon.com/Change-Anything-Science-Personal-Success/dp/0446573906/?tag=aflyingmachin-20"&gt;&amp;quot;Change Anything&amp;quot;&lt;/a&gt;
is probably the best book I&amp;#39;ve read on developing new habits.&lt;/p&gt;

&lt;p&gt;I hope you find this helpful!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:www.flyingmachinestudios.com,2012-08-26:/programming/three-dev-tools/</id>
    <title type="html">Three Dev Tools You Probably Already Know</title>
    <published>2012-08-26T23:55:00Z</published>
    <updated>2012-08-26T23:55:00Z</updated>
    <link rel="alternate" href="http://www.flyingmachinestudios.com/programming/three-dev-tools/" />
    <content type="html">&lt;p&gt;You probably already know about the following tools, but I found it
useful to be reminded of them:repl&lt;/p&gt;

&lt;h2&gt;Partitioning&lt;/h2&gt;

&lt;p&gt;Partitioning is effective as a strategy to combat complexity and scale when two conditions are true: first, the divided parts must be sufficiently small that a person can now solve them; second, it must be possible to reason about how the parts assemble into a whole. Parts that are encapsulated are easier to reason about, because you need to track fewer details when composing the parts into a solution. You can forget, at least temporarily, about the details inside the other parts. This allows the developer to more easily reason about how the parts will interact with each other.&lt;/p&gt;

&lt;h2&gt;Knowledge&lt;/h2&gt;

&lt;p&gt;Software developers use knowledge of prior problems to help them solve current ones. This knowledge can be implicit know-how or explicitly written down. It can be specific, as in which components work well with others, or general, as in techniques for optimizing a database table layout. It comes in many forms, including books, lectures, pattern descriptions, source code, design documents, or sketches on a whiteboard.&lt;/p&gt;

&lt;h2&gt;Abstraction&lt;/h2&gt;

&lt;p&gt;Abstraction can effectively combat complexity and scale because it shrinks problems, and smaller problems are easier to reason about. If you are driving from New York to Los Angeles, you can simplify the navigation problem by considering only highways. By hiding details (excluding the option of driving across fields or parking lots), you have shrunken the number of options to consider, making the problem easier to reason about.&lt;/p&gt;

&lt;p&gt;From &lt;em&gt;Just Enough Software Architecture: A Risk-Driven Approach&lt;/em&gt; by George H. Fairbanks&lt;/p&gt;
</content>
  </entry>
</feed>
