<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>mcrammm.com</title>
    <link>http://mcramm.com/index.xml</link>
    <description>Recent content on mcrammm.com</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Sat, 15 Apr 2017 13:21:00 -0700</lastBuildDate>
    <atom:link href="http://mcramm.com/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Mailfeed In Retrospect</title>
      <link>http://mcramm.com/post/mailfeed-in-retrospect/</link>
      <pubDate>Sat, 15 Apr 2017 13:21:00 -0700</pubDate>
      
      <guid>http://mcramm.com/post/mailfeed-in-retrospect/</guid>
      <description>

&lt;p&gt;It&amp;rsquo;s been a few weeks since I &lt;a href=&#34;https://www.reddit.com/r/Clojure/comments/60lqvw/my_first_clojure_production_app_mailfeed&#34;&gt;announced on /r/Clojure&lt;/a&gt; I was finished working on Mailfeed, a service that emails you whenever an RSS feed updates. A comment on that thread suggested that I share a little about the technologies I used and some of the pitfalls I hit during development.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s a lot to talk about, so I thought I&amp;rsquo;d just drop a nice big list of all the major tech, services and libraries, then move on to some of the more interesting challenges.&lt;/p&gt;

&lt;p&gt;Major Tech used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clojure(script)&lt;/li&gt;
&lt;li&gt;Postgres&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stathat&lt;/li&gt;
&lt;li&gt;Rollbar&lt;/li&gt;
&lt;li&gt;Papertrail&lt;/li&gt;
&lt;li&gt;Mailgun&lt;/li&gt;
&lt;li&gt;Digital Ocean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ring&lt;/li&gt;
&lt;li&gt;Compojure&lt;/li&gt;
&lt;li&gt;Enlive (for emails)&lt;/li&gt;
&lt;li&gt;Hiccup (for everything else)&lt;/li&gt;
&lt;li&gt;HugSQL&lt;/li&gt;
&lt;li&gt;Ragtime&lt;/li&gt;
&lt;li&gt;Environ&lt;/li&gt;
&lt;li&gt;Quartzite&lt;/li&gt;
&lt;li&gt;Buddy&lt;/li&gt;
&lt;li&gt;Component&lt;/li&gt;
&lt;li&gt;clj-time&lt;/li&gt;
&lt;li&gt;clj-stripe&lt;/li&gt;
&lt;li&gt;clj-http&lt;/li&gt;
&lt;li&gt;clj-rollcage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The meat of the application is in the worker and the web apps. Both of these are
written entirely in Clojure with a &lt;em&gt;little&lt;/em&gt; Clojurescript on one page in the
web app. I chose Postgres as a database simply because I already knew it really
 well.&lt;/p&gt;

&lt;h2 id=&#34;rss-processing-woes&#34;&gt;RSS Processing Woes&lt;/h2&gt;

&lt;p&gt;The first iteration of Mailfeed was basically the same app that exists
today with the worker existing as a background thread that was spun up whenever
the app booted. I designed the system using
&lt;a href=&#34;https://github.com/stuartsierra/component&#34;&gt;Component&lt;/a&gt; early on, and
although I had a couple of small trip-ups along the way, I&amp;rsquo;m very glad that I
chose it.&lt;/p&gt;

&lt;p&gt;At that time the worker was very un-optimized, generated a lot
of errors, and died from time to time. Rebooting it meant rebooting the whole
application and this made the engineer in me cry. The worker is the &lt;em&gt;core&lt;/em&gt; of the application; it does a lot of heavy lifting and is the main reason anyone would ever want to
actually use the service.&lt;/p&gt;

&lt;p&gt;In my first spike I tried to convert the worker to using
&lt;a href=&#34;https://github.com/clojure/core.async&#34;&gt;core.async&lt;/a&gt;, but it started to feel like the wrong solution pretty quick. The library is more about communication
between two processes and what I wanted was a completely independent process that
would:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Query the database at a regular interval&lt;/li&gt;
&lt;li&gt;Get any feeds that needed to be updated&lt;/li&gt;
&lt;li&gt;Process new entries for these feeds&lt;/li&gt;
&lt;li&gt;Send any relevant emails to subscribers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On my next spike I sat down and wrote a &amp;ldquo;Scheduler&amp;rdquo; component in &lt;a href=&#34;http://clojurequartz.info&#34;&gt;Quartzite&lt;/a&gt;, abstracting the task of feed refreshing into it&amp;rsquo;s own job. I peppered in some error handling to ensure that &lt;strong&gt;when&lt;/strong&gt; an error occurred, the job could clean up and continue. I made sure to fire the error off to &lt;a href=&#34;https://rollbar.com&#34;&gt;Rollbar&lt;/a&gt; as I still wanted visibility on them.&lt;/p&gt;

&lt;p&gt;Everything worked but the process was still really slow. At the time I had around 30 feeds that I wanted to refresh every 5 minutes. On average, the job was completing in about 40 seconds with an occasional spike up into 2 minutes. This was &lt;em&gt;technically&lt;/em&gt; still within my acceptable time frame, but still felt a little extreme for such a small number of feeds. I added in some monitoring, sending the processing times of a few different functions to &lt;a href=&#34;http://stathat.com&#34;&gt;StatHat&lt;/a&gt;, and left it for a few days to get a good baseline. I blocked off my next weekend to investigate and see what improvements could be made.&lt;/p&gt;

&lt;p&gt;When I sat down on Saturday morning I poked around and determined the job was spending most of its time waiting for a response from a few different sites. Everything else was pretty speedy. Since network latency was completely outside of my ability to correct, I decided to look at parallelizing the feed fetching/processing task. I went back to core.async very briefly again, before remembering about &lt;a href=&#34;https://clojuredocs.org/clojure.core/pmap&#34;&gt;pmap&lt;/a&gt;. I made the switch from:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;dorun &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;update-feed&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get-feeds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;To:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;dorun &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pmap&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;update-feed&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get-feeds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;After a lot more testing to make sure I hadn&amp;rsquo;t missed anything, I found that I had brought the average total processing time for the job down to 2 seconds.&lt;/p&gt;

&lt;p&gt;Woo hoo!&lt;/p&gt;

&lt;p&gt;I decided to call that &amp;ldquo;mission accomplished&amp;rdquo; and closed my computer to go make breakfast. Even now with almost 3 times the number of feeds, the mean time for the job to complete is 3.113 seconds.&lt;/p&gt;

&lt;h2 id=&#34;the-monolith-with-two-doors&#34;&gt;The Monolith with Two Doors&lt;/h2&gt;

&lt;p&gt;At this point I was really happy with how the worker was performing, but still felt like it made sense to completely separate the worker from the web app in production. I wanted them to be able to exist on their own boxes so that I could fine tune each individually.&lt;/p&gt;

&lt;p&gt;I mentioned previously that I was using component to try and keep the logical
pieces of Mailfeed as separate as possible. With Component you create &amp;ldquo;systems&amp;rdquo;
which is basically just a way of describing all your components and the
components they depend on to do their job. What I had was two systems
that shared a lot of the same components, but whose primary functions were
quite different.&lt;/p&gt;

&lt;p&gt;So that&amp;rsquo;s what I created. The &amp;ldquo;Web System&amp;rdquo; contained the all the routes, the
web handler, the database and the mailer, while the &amp;ldquo;Worker System&amp;rdquo; contained
the scheduler, the database, the mailer and the feed parser. When I go to
deploy, I build two JARs in &lt;a href=&#34;http://boot-clj.com&#34;&gt;Boot&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;deftask&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;build-web&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
 &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;comp &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;aot&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:namespace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;#39;#&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;mailfeed.web.core&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;uber&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;jar&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:main&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;mailfeed.web.core&lt;/span&gt;
       &lt;span class=&#34;ss&#34;&gt;:file&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;mailfeed-web.jar&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;target&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:dir&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;target/web&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;deftask&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;build-worker&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
 &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;comp &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;aot&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:namespace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;#39;#&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;mailfeed.worker.core&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;uber&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;jar&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:main&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;&amp;#39;mailfeed.worker.core&lt;/span&gt;
       &lt;span class=&#34;ss&#34;&gt;:file&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;mailfeed-worker.jar&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;target&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:dir&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;target/worker&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Overall I&amp;rsquo;m actually really happy with this approach. The only thing I have to
be careful of is database migrations. If I make a change for one part of the
application, I need to make sure everything is backwards compatible, since there
is no mechanism for keeping both the worker and the web app in-sync. I do one
deploy, and then the other. This is mostly-OK, since it&amp;rsquo;s generally a good idea
to write a migration to &lt;em&gt;add&lt;/em&gt; a new thing, then, if you need to, write another
migration to &lt;em&gt;remove&lt;/em&gt; the old thing once you&amp;rsquo;ve verified it&amp;rsquo;s not being used
anymore.&lt;/p&gt;

&lt;p&gt;This leads me into my next topic; one that I&amp;rsquo;m not very excited to share:&lt;/p&gt;

&lt;h1 id=&#34;deployment&#34;&gt;Deployment&lt;/h1&gt;

&lt;p&gt;Right now Mailfeed is deployed to &lt;a href=&#34;https://www.digitalocean.com/&#34;&gt;Digital Ocean&lt;/a&gt;. Everything is deployed with a couple of shell scripts and some preconfigured
&amp;ldquo;droplets&amp;rdquo; that I set up by hand then took snapshots of.&lt;/p&gt;

&lt;p&gt;The above sentence should have made you go:&lt;/p&gt;

&lt;p&gt;&lt;img
style=&#34;width: 30em&#34;
src=&#34;https://cloud.githubusercontent.com/assets/150988/24832190/5f719e88-1c67-11e7-8d44-e3ddec4b3dba.jpg&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Yeah&amp;hellip; I&amp;rsquo;m right there with you. Dumb! Dumb. Baaad Mike.&lt;/p&gt;

&lt;p&gt;But it works! I ran a failure-scenario a couple of months ago and I managed to
get everything up and running again within 30 minutes. That&amp;rsquo;s not &amp;hellip; great, but
considering how mission-critical the application is, it&amp;rsquo;s not bad either.
And if I had paying customers then I would spend the time to rework everything
through Ansible.&lt;/p&gt;

&lt;p&gt;If I was starting again today, then Ansible would definitely be technology I would consider to provision these servers for me. I&amp;rsquo;ve used in the past and had very a very good experience with it. Daniel Higginbotham has also recently released a book &amp;ldquo;&lt;a href=&#34;https://gum.co/gHcWk&#34;&gt;Deploying Your First Clojure App &amp;hellip;From the Shadows&lt;/a&gt;&amp;ldquo;
that I &lt;em&gt;wish&lt;/em&gt; had existed before I started Mailfeed.&lt;/p&gt;

&lt;h1 id=&#34;monitoring&#34;&gt;Monitoring&lt;/h1&gt;

&lt;p&gt;I&amp;rsquo;ve written a bit about monitoring, but in summary I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track of errors with Rollbar&lt;/li&gt;
&lt;li&gt;Send some key stats with Stathat&lt;/li&gt;
&lt;li&gt;Monitor hardware with Digital Ocean Monitoring&lt;/li&gt;
&lt;li&gt;Logs with Papertrail&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I experimented a bit with Riemann early on but found it was a little over my head at the time. It certainly seems capable of tracking most of the above, without the limitations imposed by having to stick to the Free account tiers.&lt;/p&gt;

&lt;h1 id=&#34;what-s-the-lesson&#34;&gt;What&amp;rsquo;s the lesson?&lt;/h1&gt;

&lt;p&gt;I was really happy with using Clojure and I didn&amp;rsquo;t have any huge surprises during development. But every story should have a lesson! I think the big lessons I learned weren&amp;rsquo;t really related to the actual development process, but more to the things that need to go along around it. If I had to pick something I needed to improve it would be to do a little more up front market research and planning instead of just jumping in and building something I and a few friends of mine wanted.&lt;/p&gt;

&lt;p&gt;Hopefully some of that was insightful. If you&amp;rsquo;re reading this and are curious about something specific, please don&amp;rsquo;t hesitate to reach out on &lt;a href=&#34;https://twitter.com/cramm&#34;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Integration Testing with Clojure and Postgres</title>
      <link>http://mcramm.com/post/integration-tests-for-clojure-and-postgres/</link>
      <pubDate>Wed, 14 Dec 2016 14:33:00 -0600</pubDate>
      
      <guid>http://mcramm.com/post/integration-tests-for-clojure-and-postgres/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;re writing a non-trivial application that will run in production, it&amp;rsquo;s usually a good idea
to have some automated way to make sure that all the pieces are working together
correctly. On a lot of projects this is going to mean integration tests. How
granular these tests become will depend on your level of paranoia and &lt;em&gt;how&lt;/em&gt;
critical those integration points are to your application as a whole.&lt;/p&gt;

&lt;p&gt;In this post I&amp;rsquo;m going to use an example &lt;a href=&#34;http://mcramm.com/post/off-the-ground-with-clojure-and-postgres/&#34;&gt;from a previous
article&lt;/a&gt; and add
some integration tests to ensure that we&amp;rsquo;re creating and updating accounts
correctly.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s worth noting that my opinion on integration tests is that they should act as &lt;em&gt;smoke&lt;/em&gt;
tests, except in some extreme cases. If you find yourself testing complex
business logic and needing to integrate with the database to do so, then chances
are you&amp;rsquo;re doing something wrong. Integration tests should not be a replacement
for QA or to compensate for bad design. But the world isn&amp;rsquo;t perfect, and sometimes
a convoluted, slow running set of integration tests is the best you can do.&lt;/p&gt;

&lt;p&gt;Alright, enough postulating. Let&amp;rsquo;s move on.  Here is the namespace that we&amp;rsquo;ll be
targeting for our tests:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.entities.accounts&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;clj-time.jdbc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.sql&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.components.postgres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres_example.components.postgres&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;Postgres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;


&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defprotocol &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;AccountOps&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-opened!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-closed!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;sql-&amp;gt;account&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;when &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
               &lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
               &lt;span class=&#34;ss&#34;&gt;:created-at&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:created_at&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
               &lt;span class=&#34;ss&#34;&gt;:updated-at&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:updated_at&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;opened-status&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;closed-status&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;closed&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;extend-protocol&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;AccountOps&lt;/span&gt;
  &lt;span class=&#34;nv&#34;&gt;Postgres&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/account-by-id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:uri&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
        &lt;span class=&#34;nv&#34;&gt;sql-&amp;gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/insert-account!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:uri&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-opened!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/update-account!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:uri&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                       &lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;opened-status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-closed!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/update-account!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:uri&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                       &lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;closed-status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This namespace&amp;rsquo;s sole responsibility is to provide a touchpoint for the rest of
our app to &lt;em&gt;where&lt;/em&gt; we&amp;rsquo;re storing our accounts data. This is where we go when we
need to fetch or update something in our database. The reason we defined the
&lt;code&gt;AccountOps&lt;/code&gt; protocol is that we may want to extend these operations over a
different store, like an AtomStore, when we move on to writing tests for other
pieces of the system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I think it&amp;rsquo;s worth mentioning that I feel like there could be a good fit
for &lt;a href=&#34;http://clojure.org/about/spec&#34;&gt;clojure.spec&lt;/a&gt; here. I&amp;rsquo;ll probably explore
this in a future post.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To start we&amp;rsquo;ll need some way to actually run our tests, both from the REPL and
outside if it. For outside the REPL, we can just use &lt;code&gt;lein test&lt;/code&gt;. For inside
though, we&amp;rsquo;re going to add a &lt;code&gt;test&lt;/code&gt; method to &lt;code&gt;dev/user.clj&lt;/code&gt; that uses the
awesome &lt;a href=&#34;https://github.com/weavejester/eftest&#34;&gt;Eftest&lt;/a&gt; to find and run our
tests.&lt;/p&gt;

&lt;p&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;; ... truncated ...&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;test &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;path &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;test/postgres_example/integration&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;eftest/run-tests&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;eftest/find-tests&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;Note that I had to make some other changes here as well to ensure that we have a
separate test database loaded up and migrated to the same version we&amp;rsquo;re
developing against. For the full list of changes to this file, see &lt;a href=&#34;https://github.com/mcramm/postgres-example/commit/0c1fbe527b442ebdbc342385cc75b0beef2171fc#diff-f83d20da641ba06134b62eab278aa907&#34;&gt;this
commit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s make sure this is working with a dummy test. Create a file at
&lt;code&gt;test/postgres_example/integration/entities/accounts.clj&lt;/code&gt; and add the following
content:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.integration.entities.accounts&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;clojure.test&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;deftest&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;foo-test&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;testing&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;our setup&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;= &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Running &lt;code&gt;(test)&lt;/code&gt; at the REPL should display a failure. If it didn&amp;rsquo;t, then you
should stop here and figure out why. If the test failed successfully,
we can move on to writing something a little more useful. We&amp;rsquo;re going to write this
test &lt;em&gt;first&lt;/em&gt;, then figure out some of the missing pieces in a minute.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.integration.entities.accounts&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;clojure.test&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.entities.accounts&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;deftest&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;create!-test&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;testing&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;create! creates and returns an account&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;not &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;nil? &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;= &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Pretty easy right? All we&amp;rsquo;re doing with this test is ensuring that the result
of calling &lt;code&gt;create!&lt;/code&gt; returns a map that has an &lt;code&gt;:account/id&lt;/code&gt; set, and was assigned
the correct status. But as I said, we&amp;rsquo;re missing a couple of things. First, we
haven&amp;rsquo;t defined what &lt;code&gt;store&lt;/code&gt; is in this context. Second, we should be cleaning up
any data we create once the test is completed.&lt;/p&gt;

&lt;p&gt;To handle both of these problem we&amp;rsquo;re going to create a &lt;code&gt;test-helpers&lt;/code&gt; namespace that
our tests can reference to get a copy of the &lt;code&gt;store&lt;/code&gt; (that we&amp;rsquo;ll point at our
test database), and we&amp;rsquo;ll create a
&lt;a href=&#34;https://clojuredocs.org/clojure.test/use-fixtures&#34;&gt;fixture&lt;/a&gt; that will execute some code
to clean up any test data:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.test-helpers&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;clojure.java.jdbc&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;jdbc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;environ.core&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.components.postgres&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;postgres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;^&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:dynamic&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;test-db-uri&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:database-url&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;_test&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db-transaction-fixture&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;jdbc/with-db-transaction&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;conn&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;test-db-uri&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;jdbc/db-set-rollback-only!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;binding &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;postgres/build&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;From the top down, we create a dynamic var for &lt;code&gt;store&lt;/code&gt; that we&amp;rsquo;ll re-bind to a
new connection for every test. That connection will happen to be a database
transaction that we&amp;rsquo;ll instruct to rollback when it&amp;rsquo;s complete, instead of
simply comitting.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Credit to &lt;a href=&#34;http://www.lispcast.com/clojure-database-test-faster&#34;&gt;this post by Eric
Normand&lt;/a&gt;. Prior to this I
had been using an &lt;code&gt;atom&lt;/code&gt; instead of a dynamic var and was pulling my hair out
trying to get my tests to run without hitting concurrency issues. Changing it to
a dynamic var and leveraging &lt;code&gt;binding&lt;/code&gt; made things quite a bit nicer. (and quite a bit faster too)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We&amp;rsquo;ll need to require this namespace in our test, and tell our tests to use this
&lt;code&gt;db-transaction-fixture&lt;/code&gt; fixture:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.integration.entities.accounts&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;clojure.test&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.test-helpers&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;db-transaction-fixture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.entities.accounts&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;use-fixtures&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:each&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;db-transaction-fixture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;deftest&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;create!-test&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;testing&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;create! creates and returns an account&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;not &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;nil? &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;= &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Running &lt;code&gt;(test)&lt;/code&gt; at the repl should be successful now. Let&amp;rsquo;s fill out the rest
of our tests. I&amp;rsquo;m going to include the whole thing since it&amp;rsquo;s so short:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.integration.entities.accounts&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;clojure.test&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.test-helpers&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;db-transaction-fixture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres-example.entities.accounts&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;use-fixtures&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:each&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;db-transaction-fixture&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;deftest&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;create!-test&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;testing&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;create! creates and returns an account&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;not &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;nil? &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;= &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;deftest&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;by-id-test&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;testing&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;by-id returns the correct account by id&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;= &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;
             &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;deftest&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;set-opened!-test&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;testing&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;set-opened! sets an account&amp;#39;s status to opened-status&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;closed&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-opened!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;= &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;opened-status&lt;/span&gt;
             &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/status&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))))))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;deftest&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;set-closed!-test&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;testing&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;set-closed! sets an account&amp;#39;s status to closed-status&amp;quot;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-closed!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;= &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;closed-status&lt;/span&gt;
             &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/status&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;These 4 tests run in about 0.022 seconds on my machine. If you check your local postgres
database, you should (hopefully) see that your accounts table is empty:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-psql&#34; data-lang=&#34;psql&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;$&lt;/span&gt; psql -U postgres_example postgres_example_test

&lt;span class=&#34;gp&#34;&gt;postgres_example_test=#&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;select&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;accounts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;┌────┬────────┬────────────┬────────────┐&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│ id │ status │ created_at │ updated_at │&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;├────┼────────┼────────────┼────────────┤&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;└────┴────────┴────────────┴────────────┘&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;(0 rows)&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;Time: 1.330 ms&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;id&lt;/code&gt; column is an auto-incrementing sequence though, so you should still see
that changing:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-postgres-console&#34; data-lang=&#34;postgres-console&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;gp&#34;&gt;postgres_example_test=#&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;select&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;currval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;accounts_id_seq&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regclass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;┌─────────┐&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│ currval │&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;├─────────┤&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;│      47 │&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;└─────────┘&lt;/span&gt;
&lt;span class=&#34;go&#34;&gt;(1 row)&lt;/span&gt;

&lt;span class=&#34;go&#34;&gt;Time: 1.910 ms&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;I&amp;rsquo;ll reiterate that integration tests should be used sparingly, and only in
critical places where two or more &lt;em&gt;things&lt;/em&gt; are interacting together. This
pattern is the same one I apply to all Clojure projects that interact with
Postgres.&lt;/p&gt;

&lt;p&gt;Hopefully this has been helpful to someone :). If you notice any errors in this
post, &lt;a href=&#34;https://twitter.com/cramm&#34;&gt;please let me know&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Off the ground with Clojure and Postgres</title>
      <link>http://mcramm.com/post/off-the-ground-with-clojure-and-postgres/</link>
      <pubDate>Mon, 12 Dec 2016 20:10:00 -0600</pubDate>
      
      <guid>http://mcramm.com/post/off-the-ground-with-clojure-and-postgres/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been writing a few apps in my spare time, most notably
&lt;a href=&#34;https://mailfeedapp.com&#34;&gt;Mailfeed&lt;/a&gt;, and I&amp;rsquo;ve developed a simple pattern
whenever I need to pull data out of the database.  This pattern could be be
applied to any database you&amp;rsquo;re interacting with, but in this case I&amp;rsquo;ll be
showing how I &lt;em&gt;tend&lt;/em&gt; to do it with Postrges.&lt;/p&gt;

&lt;p&gt;I should say that none of this is groundbreaking stuff.  If you&amp;rsquo;re an
experienced developer then you&amp;rsquo;ll probably be saying &amp;ldquo;duh&amp;rdquo; a lot, but if your
playing with Clojure and are struggling to come up with a good structure on how
to do this kind of thing, then maybe this is something you could apply.&lt;/p&gt;

&lt;p&gt;This is going to be pretty quick. Lets say you&amp;rsquo;re tracking user
accounts with a status. We&amp;rsquo;d like to be able to do the following:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;accounts/by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; nil&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;accounts/create!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; #:account{:id 1,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :status &amp;quot;open&amp;quot;,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :created-at &amp;quot;&amp;lt;some-instant-in-time&amp;gt;&amp;quot;,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :updated-at &amp;quot;&amp;lt;some-instant-in-time&amp;gt;&amp;quot;}&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;accounts/set-closed!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;accounts/by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; #:account{:id 1,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :status &amp;quot;closed&amp;quot;,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :created-at &amp;quot;&amp;lt;some-instant-in-time&amp;gt;&amp;quot;,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :updated-at &amp;quot;&amp;lt;some-instant-in-time&amp;gt;&amp;quot;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note that the resulting representation of accounts and invoices is a namespaced map, which is new to Clojure 1.9.
It&amp;rsquo;s exactly the same as:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
 &lt;span class=&#34;ss&#34;&gt;:account/status&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;closed&amp;quot;&lt;/span&gt;
 &lt;span class=&#34;ss&#34;&gt;:account/created-at&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;&amp;lt;some-instant-in-time&amp;gt;&amp;quot;&lt;/span&gt;
 &lt;span class=&#34;ss&#34;&gt;:account/updated-at&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;&amp;lt;some-instant-in-time&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let&amp;rsquo;s tackle this top-down by defining a protocol for the operations we&amp;rsquo;re performing.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.entities.accounts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defprotocol &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;AccountOps&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-opened!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-closed!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Okay that was easy, but what the heck is &lt;code&gt;this&lt;/code&gt; going to be in the context of the final implementations of
these methods? At this point it doesn&amp;rsquo;t &lt;em&gt;really&lt;/em&gt; matter. We could define a new record called &lt;code&gt;AtomStore&lt;/code&gt; and
extend our protocol over it, but that isn&amp;rsquo;t the point of this post. I&amp;rsquo;ll leave that as an exercise for the
reader.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;re going to jump right in and create a &lt;code&gt;Postgres&lt;/code&gt; component that will be passed a connection string to a
running postgres instance, with a database already created. &lt;a href=&#34;https://github.com/mcramm/postgres-example&#34;&gt;I have a full example here&lt;/a&gt; that
also sets up &lt;a href=&#34;https://github.com/weavejester/ragtime&#34;&gt;Ragtime&lt;/a&gt; to ensure the necessary schema exists.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.components.postgres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defrecord &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;Postgres&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;uri&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;build&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;uri&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;-&amp;gt;Postgres&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;uri&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;At this point we could switch back to our accounts namespace and extend the AccountOps protocol over it, but
we still need some way of actually querying our database. For that we&amp;rsquo;re going to use &lt;a href=&#34;http://www.hugsql.org&#34;&gt;HugSQL&lt;/a&gt; which will
will let us define our queries in raw sql.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s start with writing a query to look up an account by an id. Open a new file at &lt;code&gt;resources/sql/accounts.sql&lt;/code&gt;
and add the following content:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;-- :name account-by-id :? :1&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- :doc Get an account by id&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;SELECT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;accounts&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;WHERE&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;HugSQL will parse this file and define a new function called &lt;code&gt;account-by-id&lt;/code&gt; in whatever namespace we load it
in. The &lt;code&gt;:?&lt;/code&gt; marks it as a query and the &lt;code&gt;:1&lt;/code&gt; will cause it to only return 1
result.&lt;/p&gt;

&lt;p&gt;Now we&amp;rsquo;ll create a namespace to define this function in:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.sql&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;hugsql.core&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;hugsql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;hugsql/def-db-fns&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;sql/accounts.sql&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;After loading this namespace, we&amp;rsquo;ll then have a function we can call to load an account by an id:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.sql&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/account-by-id&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;your-database-uri&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;123&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Hurray! It worked&amp;hellip; kinda. Let&amp;rsquo;s define a way to create a new account with an
initial status:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;-- :name insert-account! :&amp;lt;! :1&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- :doc Inserts an account and returns the id&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;INSERT&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;INTO&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;accounts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;VALUES&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;RETURNING&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You&amp;rsquo;ll have to reload your REPL if you&amp;rsquo;re following along at one. This will define a new method called
&lt;code&gt;insert-account!&lt;/code&gt; and return the id of the row that was just inserted. Now you can do the following:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.sql&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/insert-account!&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;your-database-uri&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; {:id 1}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/account-by-id&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;your-database-uri&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; {:id 1, :status &amp;quot;open&amp;quot;, :created_at #inst &amp;quot;2016-12-12T00:00:00.000000000-00:00&amp;quot;, :updated_at #inst &amp;quot;2016-12-12T00:00:00.000000000-00:00&amp;quot;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your database uri should look something like
&lt;code&gt;postgresql://postgres_example:secret@localhost:5432/postgres_example&lt;/code&gt;,
assuming you&amp;rsquo;ve created a user &lt;code&gt;postgres_example&lt;/code&gt; with the password &lt;code&gt;secret&lt;/code&gt;,
and a dabaase with the same name. This dosen&amp;rsquo;t &lt;em&gt;have&lt;/em&gt; to be a connection
string, but it&amp;rsquo;s the most straightforward way of specifying the connection
details that I&amp;rsquo;ve encountered so far.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Switch back to our accounts namespace and use these functions in our AccountOps protocol:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.entities.accounts&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.components.postgres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.sql&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my_project.components.postgres&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;Postgres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defprotocol &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;AccountOps&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-opened!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-closed!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;extend-protocol&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;AccountOps&lt;/span&gt;
  &lt;span class=&#34;nv&#34;&gt;Postgres&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/account-by-id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db-spec&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}))&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/insert-account!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db-spec&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note that I haven&amp;rsquo;t implemented the &lt;code&gt;set-closed!&lt;/code&gt; or &lt;code&gt;set-opened!&lt;/code&gt; protocols
yet. We&amp;rsquo;ll get to them in a minute.&lt;/p&gt;

&lt;p&gt;Because this example is a little contrived, the solution here seems almost
too straightforward. The only interesting piece is that &lt;code&gt;create!&lt;/code&gt;
passes it&amp;rsquo;s result immediately to &lt;code&gt;by-id&lt;/code&gt; for re-fetching. This is a design
decision I&amp;rsquo;m making; your needs may vary.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;re missing something though. Remember our example at the beginning of this article returned us a namespaced
map, but we&amp;rsquo;re getting back just a regular one. To do this we&amp;rsquo;re going to pass
every result of &lt;code&gt;sql/account-by-id&lt;/code&gt; through a function &lt;code&gt;sql-&amp;gt;account&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.entities.accounts&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.components.postgres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.sql&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my_project.components.postgres&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;Postgres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defprotocol &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;AccountOps&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-opened!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-closed!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;sql-&amp;gt;account&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;when &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;         &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
              &lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt;     &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
              &lt;span class=&#34;ss&#34;&gt;:created-at&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:created_at&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
              &lt;span class=&#34;ss&#34;&gt;:updated-at&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:updated_at&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql-entity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;extend-protocol&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;AccountOps&lt;/span&gt;
  &lt;span class=&#34;nv&#34;&gt;Postgres&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/account-by-id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db-spec&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
        &lt;span class=&#34;nv&#34;&gt;sql-&amp;gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;create!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/insert-account!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db-spec&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;It&amp;rsquo;s usually a good idea to insulate your code from outside dependencies like
the database. Here we&amp;rsquo;re taking the raw result returned to us from HugSQL and
mapping it to our own internal representation of it. This also gives us a place
to manipulate the data to suite our needs as it comes out of the database.&lt;/p&gt;

&lt;p&gt;There is one more thing I would recommend doing at this point, and it would be
to require &lt;code&gt;clj-time.jdbc&lt;/code&gt; in our accounts namespace:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.entities.accounts&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;clj-time.jdbc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.components.postgres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.sql&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;sql&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my_project.components.postgres&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;Postgres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The &lt;a href=&#34;https://github.com/clj-time/clj-time&#34;&gt;clj-time&lt;/a&gt; library is great on it&amp;rsquo;s
own, and including this namespace will ensure that as the JDBC library pulls
dates out of the database, that they&amp;rsquo;re mapped to JodaTime instances.&lt;/p&gt;

&lt;p&gt;Now we&amp;rsquo;re finally ready to give these a try:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;accounts/by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; nil&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;accounts/create!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; #:account{:id 1,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :status &amp;quot;open&amp;quot;,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :created-at #object[org.joda.time.DateTime 0x17dffb5 &amp;quot;2016-12-12T00:00:00.000Z&amp;quot;],&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :updated-at #object[org.joda.time.DateTime 0x7e0ac645 &amp;quot;2016-12-12T00:00:00.000Z&amp;quot;]}&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;accounts/by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; #:account{:id 1,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :status &amp;quot;open&amp;quot;,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :created-at #object[org.joda.time.DateTime 0x17dffb5 &amp;quot;2016-12-12T00:00:00.000Z&amp;quot;],&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :updated-at #object[org.joda.time.DateTime 0x7e0ac645 &amp;quot;2016-12-12T00:00:00.000Z&amp;quot;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Success! The last thing we&amp;rsquo;ll do is implement our &lt;code&gt;set-*&lt;/code&gt; functions.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;;; ========================================&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;; in my-project.entities.accounts&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;opened-status&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;open&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;closed-status&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;closed&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;extend-protocol&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;AccountOps&lt;/span&gt;
  &lt;span class=&#34;nv&#34;&gt;Postgres&lt;/span&gt;
  &lt;span class=&#34;c1&#34;&gt;;; ... truncated ...&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-closed!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/update-account!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:uri&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                       &lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;closed-status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;set-open!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sql/update-account!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:uri&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                       &lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;opened-status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;-- ========================================&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- in resources/sql/accounts.sql&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;-- :name update-account! :&amp;lt; :1&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;-- :doc Updates an account by id&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;UPDATE&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;accounts&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;SET&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;updated_at&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;WHERE&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;RETURNING&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And let&amp;rsquo;s try them out:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-account&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;accounts/by-id&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;my-account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; &amp;quot;open&amp;quot;&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;accounts/set-closed!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;my-account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; #:account{:id 1,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :status &amp;quot;closed&amp;quot;,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :created-at #object[org.joda.time.DateTime 0x17dffb5 &amp;quot;2016-12-12T00:00:00.000Z&amp;quot;],&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :updated-at #object[org.joda.time.DateTime 0x7e0ac645 &amp;quot;2016-12-12T00:00:00.000Z&amp;quot;]}&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;;; Note that `my-account` hasen&amp;#39;t changed&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:account/status&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;my-account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; &amp;quot;open&amp;quot;&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;accounts/set-opened!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;store&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;my-account&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;; =&amp;gt; #:account{:id 1,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :status &amp;quot;open&amp;quot;,&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :created-at #object[org.joda.time.DateTime 0x17dffb5 &amp;quot;2016-12-12T00:00:00.000Z&amp;quot;],&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;;              :updated-at #object[org.joda.time.DateTime 0x7e0ac645 &amp;quot;2016-12-12T00:00:00.000Z&amp;quot;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And bam! That&amp;rsquo;s it.&lt;/p&gt;

&lt;p&gt;As I said before, this example is a little small and contrived, but I&amp;rsquo;ve found
it to be a good jumping off point for most projects to start with.&lt;/p&gt;

&lt;p&gt;If you notice any errors in this post, &lt;a href=&#34;https://twitter.com/cramm&#34;&gt;please let me know&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Datomic Setup</title>
      <link>http://mcramm.com/post/datomic-setup/</link>
      <pubDate>Wed, 22 Jul 2015 20:10:00 -0600</pubDate>
      
      <guid>http://mcramm.com/post/datomic-setup/</guid>
      <description>

&lt;p&gt;I&amp;rsquo;ve recently been exploring Datomic more seriously and have found myself
jumping through the same hoops as I have in the past &lt;em&gt;just to get things up and
running&lt;/em&gt;. I&amp;rsquo;ve also encountered slight deficiencies in the documentation that
I&amp;rsquo;ve had to re-investigate since the exploratory project I created was deleted
quite a while ago.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m tired of retracing my same steps over and over again so I thought I&amp;rsquo;d create a
quick post with some of the basic steps to get setup and using Datomic in a
Clojure application.&lt;/p&gt;

&lt;p&gt;This is just going to cover the basics. Datomic does some crazy things I haven&amp;rsquo;t
had a chance to try yet, like using &lt;a href=&#34;http://docs.datomic.com/query.html#rules&#34;&gt;rules&lt;/a&gt;, querying the database at a &lt;a href=&#34;http://docs.datomic.com/tutorial.html#working-with-time&#34;&gt;particular
instant in time&lt;/a&gt;, or &lt;a href=&#34;http://stackoverflow.com/questions/11025434/in-datomic-how-do-i-get-a-timeline-view-of-the-changes-made-to-the-values-of-a&#34;&gt;getting a list of changes to an entity&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;installing-datomic&#34;&gt;Installing Datomic&lt;/h2&gt;

&lt;p&gt;You do not need to install Datomic to get started, you can use the in-memory
database.&lt;/p&gt;

&lt;p&gt;Go here: &lt;a href=&#34;https://my.datomic.com/downloads/free&#34;&gt;https://my.datomic.com/downloads/free&lt;/a&gt; and find the latest version.&lt;/p&gt;

&lt;p&gt;Then add &lt;code&gt;[com.datomic/datomic-free &amp;quot;&amp;lt;the-latest-version&amp;gt;&amp;quot;]&lt;/code&gt; to your Leiningen project.&lt;/p&gt;

&lt;h2 id=&#34;component-setup&#34;&gt;Component Setup&lt;/h2&gt;

&lt;p&gt;This is pretty easy, but you should have something like this:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.components.datomic&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;com.stuartsierra.component&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;component&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;datomic.api&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;datomic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defrecord &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;DatomicComponent&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;uri&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;nv&#34;&gt;component/Lifecycle&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;start&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:conn&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;do&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;assoc &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:conn&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;datomic/connect&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;uri&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;stop&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;assoc &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:conn&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2 id=&#34;schema&#34;&gt;Schema&lt;/h2&gt;

&lt;p&gt;Schema should be ideally be kept in an EDN file and loaded on demand:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;schema&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;delay&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;read-string&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;slurp &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;io/resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;my_project/schema.edn&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;create-schema&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;datomic/transact&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;conn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;schema&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here is what your schema might look like:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;; resources/my_project/schema.edn&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db/id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/ident&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:cake/name&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/valueType&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.type/string&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/cardinality&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.cardinality/one&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/fulltext&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/doc&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;The name of a cake&amp;quot;&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db.install/_attribute&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.part/db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db/id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/ident&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:cake/owner&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/valueType&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.type/ref&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/cardinality&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.cardinality/one&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/doc&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;The owner of a cake&amp;quot;&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db.install/_attribute&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.part/db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db/id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/ident&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user/email&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/unique&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.unique/value&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/valueType&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.type/string&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/cardinality&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.cardinality/one&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/doc&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Email address of a user&amp;quot;&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db.install/_attribute&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.part/db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db/id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/ident&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user/phone-numbers&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/valueType&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.type/string&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/cardinality&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.cardinality/many&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db/doc&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Contact numbers for a user&amp;quot;&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:db.install/_attribute&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:db.part/db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Information on defining your schema and all the options available
is documented &lt;a href=&#34;http://docs.datomic.com/schema.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;seed-data&#34;&gt;Seed Data&lt;/h2&gt;

&lt;p&gt;Like your schema, any seed data should be kept in a separate file:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;seed-data&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;delay&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;read-string&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;slurp &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;io/resource&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;my_project/seed.edn&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;seed-db&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;conn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;datomic/transact&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;conn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;seed-data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here is what your seed data might look like:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;; resources/my_project/seed.edn&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
  &lt;span class=&#34;c1&#34;&gt;;; Users&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db/id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/user&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;-1000001&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:user/email&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;sally@test.com&amp;quot;&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:user/password&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;supersecret&amp;quot;&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:user/phones&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;8469481047&amp;quot;&lt;/span&gt;, &lt;span class=&#34;s&#34;&gt;&amp;quot;9471038596&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]}&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db/id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/user&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;-1000002&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:user/email&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;bob@test.com&amp;quot;&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:user/password&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;secret&amp;quot;&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:user/phones&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;1234567890&amp;quot;&lt;/span&gt;, &lt;span class=&#34;s&#34;&gt;&amp;quot;0987654321&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]}&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;;; Cakes&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db/id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:cake/owner&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/user&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;-1000001&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:cake/name&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Carrot&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db/id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:cake/owner&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/user&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;-1000001&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:cake/name&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Cheese&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db/id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:cake/owner&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;db/id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:db.part/user&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;-1000002&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
   &lt;span class=&#34;ss&#34;&gt;:cake/name&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Carrot&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2 id=&#34;queries-updates&#34;&gt;Queries &amp;amp; Updates&lt;/h2&gt;

&lt;p&gt;The operations to be performed on an entity should be confined to it&amp;rsquo;s own namespace:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.users&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;datomic.api&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;datomic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-project.component.datomic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;c1&#34;&gt;; Note the change from using a dash to an underscore&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my_project.component.datomic&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;DatomicComponent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defprotocol &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;UserOps&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;all&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-email&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;save!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;extend-type&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;DatomicComponent&lt;/span&gt;
  &lt;span class=&#34;nv&#34;&gt;UserOps&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;all&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;datomic/q&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:find&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pull&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;?user&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                 &lt;span class=&#34;ss&#34;&gt;:where&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;?user&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user/email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
               &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;datomic/db&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:conn&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;by-email&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;datomic/q&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:find&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pull&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;?user&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])]&lt;/span&gt;
                 &lt;span class=&#34;ss&#34;&gt;:in&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;?email&lt;/span&gt;
                 &lt;span class=&#34;ss&#34;&gt;:where&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;?user&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user/email&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;?email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
               &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;datomic/db&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:conn&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
               &lt;span class=&#34;nv&#34;&gt;email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;save!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;datomic/transact&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:conn&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;[(pull ?user [*]) ...]&lt;/code&gt; is an example of &lt;a href=&#34;http://docs.datomic.com/pull.html&#34;&gt;Datomic&amp;rsquo;s pull syntax&lt;/a&gt;. This basically says &amp;ldquo;after all &lt;code&gt;?user&lt;/code&gt;s, bring in all of their attributes. Be careful when using the wildcard &lt;code&gt;*&lt;/code&gt; as this will recursively pull any component attributes.&lt;/p&gt;

&lt;h2 id=&#34;traversing-refs-forwards-and-backwards&#34;&gt;Traversing refs forwards and backwards&lt;/h2&gt;

&lt;p&gt;It&amp;rsquo;s possible to pull in &lt;code&gt;refs&lt;/code&gt; by specifying them in the pull pattern. If you wanted cakes with their owners:&lt;/p&gt;

&lt;p&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;datomic/q&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:find&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pull&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;?cake&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;* &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:cake/owner&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]}])&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
             &lt;span class=&#34;ss&#34;&gt;:where&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;?cake&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:cake/owner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
           &lt;span class=&#34;nv&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;If however you wanted the reverse, users and their cakes:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;datomic/q&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:find&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pull&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;?user&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;* &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:cake/_owner&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]}])&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
             &lt;span class=&#34;ss&#34;&gt;:where&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;?user&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user/email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
           &lt;span class=&#34;nv&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2 id=&#34;recursive-graph-queries&#34;&gt;Recursive (graph) queries&lt;/h2&gt;

&lt;p&gt;This is one I haven&amp;rsquo;t found a good real world use case for yet, but it is possible. Read the following if you&amp;rsquo;re looking at doing these kinds of queries:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://docs.datomic.com/query.html#rules&#34;&gt;http://docs.datomic.com/query.html#rules&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://hashrocket.com/blog/posts/using-datomic-as-a-graph-database&#34;&gt;http://hashrocket.com/blog/posts/using-datomic-as-a-graph-database&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Rack and Ring Basics</title>
      <link>http://mcramm.com/post/rack-and-ring-basics/</link>
      <pubDate>Wed, 15 Apr 2015 18:04:47 -0600</pubDate>
      
      <guid>http://mcramm.com/post/rack-and-ring-basics/</guid>
      <description>

&lt;p&gt;In the Clojure world, when you want to write a web app, you will almost
certainly be using &lt;a href=&#34;https://github.com/ring-clojure/ring&#34;&gt;Ring&lt;/a&gt;. Ring is directly inspired by
&lt;a href=&#34;https://rack.github.io/&#34;&gt;Rack&lt;/a&gt;, the defacto
webserver abstraction for frameworks in Ruby.&lt;/p&gt;

&lt;p&gt;The two are conceptually very similar, but there are some slight differences
(aside from language) that might be interesting to highlight. I won&amp;rsquo;t be going
too in depth with this post, and will focus instead on the basics of using
Rack and Ring. I thought I would just get that out of the way before your
expectations got too high.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s worth noting that most apps won&amp;rsquo;t actually use either Rack or Ring
directly like we will here. It would be a lot faster and safer to use something
like &lt;a href=&#34;http://www.sinatrarb.com/&#34;&gt;Sinatra&lt;/a&gt; or &lt;a href=&#34;http://rubyonrails.org/&#34;&gt;Rails&lt;/a&gt; for Rack, and
&lt;a href=&#34;https://github.com/technomancy/compojure&#34;&gt;Compojure&lt;/a&gt; or
&lt;a href=&#34;http://www.luminusweb.net/&#34;&gt;Luminus&lt;/a&gt; for Ring.&lt;/p&gt;

&lt;p&gt;If you want to see the final versions of these examples in their full forms
please click:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mcramm/rack-basics&#34;&gt;Here for the Rack example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/mcramm/ring-basics&#34;&gt;Here for the Ring example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;the-minimal-first-step&#34;&gt;The Minimal First Step&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s start with Rack, since it&amp;rsquo;s obviously the more popular of the two.
I&amp;rsquo;m going to assume that you can
&lt;a href=&#34;https://github.com/rack/rack#installing-with-rubygems&#34;&gt;read&lt;/a&gt; and get Rack
installed if you don&amp;rsquo;t already have it. If you can&amp;rsquo;t read, then I have nothing
to worry about because this will all look like gobbledygook to you. I hope ASCII
art will serve as an appropriate apology  :-).&lt;/p&gt;

&lt;p&gt;The first step in getting either application off the ground is to create a
entry point. In the case of Rack this is will be an object with a &lt;code&gt;call&lt;/code&gt;
method. This method needs to return the basic structure required for a Rack
response, which is an array containing the response status, headers and body:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;# my_rack_app.rb&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;MyRackApp&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;200&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;text/html&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Hello World&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note how simple this is. This is just a regular old ruby object with a method
that returns a triplet. It knows nothing about Rack or anything else that might
be using it.&lt;/p&gt;

&lt;p&gt;Unfortunately this does absolutely &lt;em&gt;nothing&lt;/em&gt;, which is pretty boring.  To boot this app up, we&amp;rsquo;ll add a &lt;code&gt;config.ru&lt;/code&gt; to the current directory:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# config.ru&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;rack&amp;#39;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;require_relative&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;my_rack_app&amp;#39;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;MyRackApp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We can now run &lt;code&gt;rackup&lt;/code&gt; from our current directory and, navigating to
&lt;a href=&#34;http://localhost:9292/&#34;&gt;http://localhost:9292&lt;/a&gt;, we should see our &amp;ldquo;Hello World&amp;rdquo;
response.&lt;/p&gt;

&lt;p&gt;Getting our Ring app off the ground requires a little bit more setup, but we&amp;rsquo;ll be
using &lt;a href=&#34;http://leiningen.org/&#34;&gt;Leiningen&lt;/a&gt; to do most of the trivial stuff for us.&lt;/p&gt;

&lt;p&gt;First let&amp;rsquo;s create a new project with &lt;code&gt;lein new app my-ring-app&lt;/code&gt;. Add &lt;code&gt;[ring &amp;quot;1.3.2&amp;quot;]&lt;/code&gt; to the list of dependencies
in &lt;code&gt;project.clj&lt;/code&gt;.
You might need to run &lt;code&gt;lein deps&lt;/code&gt; to download the Ring library if you don&amp;rsquo;t already have it.&lt;/p&gt;

&lt;p&gt;Ring is similar to Rack in that we need to give it a function that returns
some standard response. Ring expects a map instead of an array:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-ring-app.app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;handler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;200&lt;/span&gt;
       &lt;span class=&#34;ss&#34;&gt;:headers&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;text/html&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
       &lt;span class=&#34;ss&#34;&gt;:body&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Calling the function &amp;ldquo;handler&amp;rdquo; above is simply the convention in Clojure-land.
Like the Rack example, we need some way to boot this app up. Some examples will
mash this boot process together with the code we wrote above but I prefer to
keep this separate. Plus it makes it similar to our Rack example so win-win,
     right?&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-ring-app.core&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ring.adapter.jetty&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;run-jetty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-ring-app.app&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:gen-class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;-main&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;run-jetty&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app/handler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:port&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now we can just do &lt;code&gt;lein run&lt;/code&gt; from our project root. Navigating to
 &lt;a href=&#34;http://localhost:3000/&#34;&gt;http://localhost:3000&lt;/a&gt; should display a very familiar page.&lt;/p&gt;

&lt;h2 id=&#34;middleware&#34;&gt;Middleware&lt;/h2&gt;

&lt;p&gt;Middleware is essentially a series a steps a request has to go through in order
 to generate a response. Once a response is generated, it will return the
 response back up through any middleware in reverse order.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;re going to introduce some middleware to both of our applications that
translates &amp;ldquo;Hello&amp;rdquo; to it&amp;rsquo;s French counterpart &amp;ldquo;Bonjour&amp;rdquo;. Why French? Well
I&amp;rsquo;m Canadian, and if I don&amp;rsquo;t provide some kind of French content, then the
CRTC might come and yell at me for not being fair.&lt;/p&gt;

&lt;p&gt;I also don&amp;rsquo;t know how to say &amp;ldquo;Hello&amp;rdquo; in any other language off the top of my
head and I&amp;rsquo;m too lazy to do any more research so we are going to stick with
&amp;ldquo;Bonjour&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;In Rack our middleware is going to be another ruby object, except that we will actually
be doing something with that &lt;code&gt;env&lt;/code&gt; parameter we saw in our earlier example. You
will notice that our middleware bears some resemblance to our running
&lt;code&gt;MyRackApp&lt;/code&gt;&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;# hello_translator.rb&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;HelloTranslator&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;initialize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;vi&#34;&gt;@app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

      &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;translate_hello&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gsub&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;/Hello/&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Bonjour&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

      &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;headers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;body&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;vi&#34;&gt;@app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;map!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;translate_hello&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
        &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;headers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;First we initialize the middleware with our running application. Calling
&lt;code&gt;@app.call(env)&lt;/code&gt; simply passes the request down the stack. If there was
another piece of middleware beneath us, then it would be the next reciever of
our &lt;code&gt;env&lt;/code&gt; parameter. This would keep going until a response is generated, which
in our case will be from &lt;code&gt;MyRackApp&lt;/code&gt; that we defined earlier. Our return value
needs to be the same status, headers and body array in order for Rack to be able
to serve the response.&lt;/p&gt;

&lt;p&gt;If you ran &lt;code&gt;rackup&lt;/code&gt; right now, then you wouldn&amp;rsquo;t see any change. This is because
we actually need to &lt;em&gt;tell&lt;/em&gt; Rack about this is middleware. To accomplish this we
need to require and &lt;code&gt;use&lt;/code&gt; it in our &lt;code&gt;config.ru&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;# config.ru&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;rack&amp;#39;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;require_relative&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;my_rack_app&amp;#39;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;require_relative&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;hello_translator&amp;#39;&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;HelloTranslator&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;MyRackApp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Running &lt;code&gt;rackup&lt;/code&gt; and refreshing the previous page will now show a lovely
greeting in the famously romantic French language.&lt;/p&gt;

&lt;p&gt;Again Ring is very similar. The biggest difference is that the middleware is
just a function instead of an object:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-ring-app.middleware&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;clojure.string&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;translate-hello&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
     &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;s/replace&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;body&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Bonjour&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wrap-hello-translator&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;fn &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;handler&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;update-in&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;response&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;translate-hello&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Again, prefixing our middleware with &lt;code&gt;wrap&lt;/code&gt; is convention.  As before we will need to require and use
this middleware in the namespace responsible for booting the app:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-ring-app.core&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ring.adapter.jetty&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;run-jetty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-ring-app.app&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-ring-app.middleware&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wrap-hello-translator&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]])&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:gen-class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;-main&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;run-jetty&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;app/handler&lt;/span&gt;
                     &lt;span class=&#34;nv&#34;&gt;wrap-hello-translator&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                 &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:port&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2 id=&#34;dealing-with-query-params&#34;&gt;Dealing With Query Params&lt;/h2&gt;

&lt;p&gt;I was originally going to end the post here with an amazingly concise, beautifully
written conclusion to tie a nice little bow over everything. Instead I&amp;rsquo;m going to
take this comparison one step further and really phone in the whole &amp;ldquo;wrapping
things up&amp;rdquo; section that is structurally necessary.&lt;/p&gt;

&lt;p&gt;I want to show something that is &lt;em&gt;much&lt;/em&gt; more common than our mostly pointless
&amp;ldquo;Hello&amp;rdquo; to &amp;ldquo;Bonjour&amp;rdquo; translation app that we&amp;rsquo;ve written. I&amp;rsquo;m going to show
you how Ring and Rack each let you access any query parameters that may have
come along with the request.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s say that we want to let the request specify who we want to say
&amp;ldquo;Bonjour&amp;rdquo; to, and &amp;ldquo;World&amp;rdquo; if nothing is provided. The request can tell us what
name to use by simply providing a &lt;code&gt;name&lt;/code&gt; parameter.&lt;/p&gt;

&lt;p&gt;With the Rack example, we aren&amp;rsquo;t going to touch anything except for our base
application:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;# my_rack_app.rb&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;MyRackApp&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Rack&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;subject&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fetch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;World&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;body&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;Hello &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;#{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subject&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;

        &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;200&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;text/html&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The change here is that we wrap the &lt;code&gt;env&lt;/code&gt; parameter in a &lt;code&gt;Rack::Request&lt;/code&gt;
object, then attempt to fetch the &lt;code&gt;&#39;name&#39;&lt;/code&gt; parameter. If one isn&amp;rsquo;t provided,
then we default to &lt;code&gt;&#39;World&#39;&lt;/code&gt;. Our response is essentially the same.&lt;/p&gt;

&lt;p&gt;Opening &lt;a href=&#34;http://localhost:9292?name=Pierre&#34;&gt;http://localhost:9292?name=Pierre&lt;/a&gt;, we should see &amp;ldquo;Bonjour Pierre&amp;rdquo;. If we omit the &lt;code&gt;name&lt;/code&gt; parameter entirely, then we should
see &amp;ldquo;Bonjour World&amp;rdquo; as before.&lt;/p&gt;

&lt;p&gt;Ring&amp;rsquo;s approach is slightly different. Instead of wrapping the request in
another object, there is a set of very common default middleware that we can
choose to include. One of these is &lt;code&gt;wrap-params&lt;/code&gt;, which will add a &lt;code&gt;:params&lt;/code&gt; key
to the request and take any parameters out of the query string and put into a
map at that key.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve included full-versions of each file here to keep things easy to follow.
Additions to &lt;code&gt;my-ring-app.core&lt;/code&gt; are noted:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-ring-app.core&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ring.adapter.jetty&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;run-jetty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ring.middleware.params&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wrap-params&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;; NEW&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-ring-app.app&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-ring-app.middleware&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;wrap-hello-translator&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]])&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:gen-class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;-main&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;run-jetty&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;app/handler&lt;/span&gt;
                     &lt;span class=&#34;nv&#34;&gt;wrap-params&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;; NEW&lt;/span&gt;
                     &lt;span class=&#34;nv&#34;&gt;wrap-hello-translator&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:port&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-ring-app.app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;handler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;subject&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get-in&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;request&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:params&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;World&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:status&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;200&lt;/span&gt;
         &lt;span class=&#34;ss&#34;&gt;:headers&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;text/html&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
         &lt;span class=&#34;ss&#34;&gt;:body&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Hello %s&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;subject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The difference between the two examples is the fact that the
query string processing is handled in middleware with Ring, while with Rack I
wrapped it. I tried to find a similar piece of middleware for Rack but
after an hour of clicking around I came up short. There is some stuff in
&lt;a href=&#34;https://github.com/rack/rack-contrib&#34;&gt;rack-contrib&lt;/a&gt; that comes close, but not
close enough.  I&amp;rsquo;m sure one exists and I&amp;rsquo;ll update this post if I can find something
analogous to Ring&amp;rsquo;s &lt;code&gt;wrap-params&lt;/code&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I hope this been at least a little bit enlightening. I found the basics of Ring and Rack to be
&lt;em&gt;so similiar&lt;/em&gt; that I couldn&amp;rsquo;t help but write a post about the two. The
differences in application structure and methodologies become more pronounced
the  more complicated your stack becomes, but this is usually due to stuff built
&lt;em&gt;on top&lt;/em&gt; of them.&lt;/p&gt;

&lt;p&gt;In future posts I hope to show something a bit more useful built with Ring.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Composing Functions</title>
      <link>http://mcramm.com/post/composing-functions/</link>
      <pubDate>Sat, 11 Apr 2015 18:04:47 -0600</pubDate>
      
      <guid>http://mcramm.com/post/composing-functions/</guid>
      <description>&lt;p&gt;Let&amp;rsquo;s look at the different flavors of function composition
in Clojure.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h2 id=&#34;comp&#34;&gt;Comp&lt;/h2&gt;

&lt;p&gt;There is a function in clojure.core called &lt;code&gt;comp&lt;/code&gt; that takes a set of
functions and returns a function that is a composition of those functions:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;doubler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;* &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;incrementer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;+ &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;doubler-and-incrementer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;comp &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;incrementer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;doubler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;doubler-and-incrementer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;; =&amp;gt; [3 5 7 9]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;clojure.core/inc&lt;/code&gt; exists, but I recreate it here to be explicit&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note that when composing functions with comp, they are applied right to left to
their arguments:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;incrementer-and-doubler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;comp &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;doubler&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;incrementer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;incrementer-and-doubler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;; =&amp;gt; [4 6 8 10]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h2 id=&#34;partial&#34;&gt;Partial&lt;/h2&gt;

&lt;p&gt;Another function in clojure.core is &lt;code&gt;partial&lt;/code&gt; that takes a function and some
arguments to that function and returns a new function that will accept the
remaining number of arguments. This can be useful when combined with comp and
writing a custom reducer:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;incrementer-and-doubler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;comp &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;partial map &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;doubler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                       &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;partial map &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;incrementer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;incrementer-and-doubler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;; =&amp;gt; [4 6 8 10]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Clojure 1.7 will introduce transducers, which will likely become the idiomatic
way of accomplishing this same task.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;threading-macros&#34;&gt;Threading Macros&lt;/h2&gt;

&lt;p&gt;A more popular method of composition are the thread-first and
thread-last macros.&lt;/p&gt;

&lt;p&gt;The thread-first macro evaluates the first expression then passes the result
into first argument of the next form, and the result of that into the first
argument of the next form and so on.&lt;/p&gt;

&lt;p&gt;In other words, this:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;doubler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;incrementer&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Is the same as this:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;incrementer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;doubler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Thread-last works the same way, but it passes the result of each expression into
the last element of each successive form.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
         &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;incrementer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
         &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;doubler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Is the same as:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;doubler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;incrementer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>Om Comparison</title>
      <link>http://mcramm.com/post/om-comparison/</link>
      <pubDate>Sat, 01 Feb 2014 18:04:47 -0600</pubDate>
      
      <guid>http://mcramm.com/post/om-comparison/</guid>
      <description>&lt;p&gt;In my &lt;a href=&#34;http://mcramm.com/2014/01/26/react-intro.html&#34;&gt;last post&lt;/a&gt; I built a simple text manipulation widget with &lt;a href=&#34;http://facebook.github.io/react/&#34;&gt;React&lt;/a&gt;.
I recommend reading through that post first, before this one.
As promised, I&amp;rsquo;ve built the same widget in
&lt;a href=&#34;https://github.com/swannodette/om&#34;&gt;Om&lt;/a&gt;, a ClojureScript library that
sits on top of React.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;If you want to follow along, you&amp;rsquo;ll need to install Leiningen and run:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span&gt;&lt;/span&gt;    lein new mies-om om-intro
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;cd&lt;/code&gt; into the new directory and make your &lt;code&gt;project.clj&lt;/code&gt; look like the following:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defproject &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;om-intro&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;0.1.0-SNAPSHOT&amp;quot;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;:description&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;FIXME: write this!&amp;quot;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;:url&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;http://example.com/FIXME&amp;quot;&lt;/span&gt;

      &lt;span class=&#34;ss&#34;&gt;:dependencies&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;org.clojure/clojure&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;1.5.1&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                     &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;org.clojure/clojurescript&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;0.0-2138&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                     &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;org.clojure/core.async&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;0.1.267.0-0d7780-alpha&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                     &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;om&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;0.3.1&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                     &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;com.facebook/react&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;0.8.0.1&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;

      &lt;span class=&#34;ss&#34;&gt;:plugins&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;lein-cljsbuild&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;1.0.1&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;

      &lt;span class=&#34;ss&#34;&gt;:source-paths&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;src&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;

      &lt;span class=&#34;ss&#34;&gt;:cljsbuild&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;:builds&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;dev&amp;quot;&lt;/span&gt;
                  &lt;span class=&#34;ss&#34;&gt;:source-paths&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;src&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                  &lt;span class=&#34;ss&#34;&gt;:compiler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:output-to&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;om_intro.js&amp;quot;&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:output-dir&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;out&amp;quot;&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:optimizations&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:none&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:source-map&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}}]})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;You will also want to update your &lt;code&gt;index.html&lt;/code&gt; look like this:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;app&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;http://fb.me/react-0.8.0.js&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;out/goog/base.js&amp;quot;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;om_intro.js&amp;quot;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;goog&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;om_intro.core&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Get any missing dependencies with &lt;code&gt;lein deps&lt;/code&gt;, then build the project with &lt;code&gt;lein
cljsbuild once dev&lt;/code&gt;. Open &lt;code&gt;index.html&lt;/code&gt; in a browser and you should see the
bare-bones example that comes with this template.&lt;/p&gt;

&lt;p&gt;For the rest of this tutorial, I recommend running &lt;code&gt;lein cljsbuild auto dev&lt;/code&gt; in
a separate terminal. The first time the project gets built takes a second or
two, but after the JVM has warmed up, it takes just milliseconds.&lt;/p&gt;

&lt;p&gt;The snippets above are for a development build of the project. The final example
I link to at the end of this post contains a release build, that generates a
single JavaScript file.&lt;/p&gt;

&lt;p&gt;With the setup out of the way we can start rebuilding this widget.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;om-intro.core&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;om.core&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;om&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:include-macros&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;om.dom&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;dom&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:include-macros&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;app-state&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;atom&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Some Text&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-widget&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;reify&lt;/span&gt;
        &lt;span class=&#34;nv&#34;&gt;om/IRender&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/div&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/root&lt;/span&gt;
      &lt;span class=&#34;nv&#34;&gt;app-state&lt;/span&gt;
      &lt;span class=&#34;nv&#34;&gt;my-widget&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;. &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;js/document&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;getElementById&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;app&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This is analogous to the first example in the React version; all we&amp;rsquo;re doing is
defining a component that renders a &lt;code&gt;div&lt;/code&gt; containing the value of &lt;code&gt;:text&lt;/code&gt; from
our application state.&lt;/p&gt;

&lt;p&gt;There are already a differences though. First, we&amp;rsquo;ve moved all of our state
into an atom. Components are given &lt;em&gt;cursors&lt;/em&gt; into this application state that
they can use to read/update.&lt;/p&gt;

&lt;p&gt;Second, our &lt;code&gt;my-widget&lt;/code&gt; component is returning a reified object that satisfies
the &lt;code&gt;om/IRender&lt;/code&gt; interface. The &lt;code&gt;render&lt;/code&gt; method simply returns the
aforementioned &lt;code&gt;div&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You should see something like this:&lt;/p&gt;

&lt;div class=&#39;highlight example&#39; id=&#34;ex1&#34;&gt; &lt;/div&gt;

&lt;p&gt;Like our first example in the React version, this is pretty boring. Let&amp;rsquo;s add
in the text input.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;re going to be using &lt;a href=&#34;https://github.com/clojure/core.async&#34;&gt;core.async&lt;/a&gt; at
the edges of our components, wherever our users will be interacting with the
various &lt;code&gt;input&lt;/code&gt;s we&amp;rsquo;ll eventually have.&lt;/p&gt;

&lt;p&gt;Change the namespace declaration to the following:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;om-intro.core&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require-macros&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cljs.core.async.macros&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]])&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;om.core&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;om&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:include-macros&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;om.dom&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;dom&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:include-macros&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;cljs.core.async&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:refer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;put!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;chan&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Then we&amp;rsquo;ll update the widget. We&amp;rsquo;re going to walk through this step-by-step in
a minute, but here is what it should look like:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-widget&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;reify&lt;/span&gt;
        &lt;span class=&#34;nv&#34;&gt;om/IInitState&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;init-state&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:comm&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:string&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;chan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}})&lt;/span&gt;

        &lt;span class=&#34;nv&#34;&gt;om/IWillMount&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;will-mount&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:keys&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]}&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/get-state&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:comm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;go&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;
                  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/transact!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;fn &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))))&lt;/span&gt;

        &lt;span class=&#34;nv&#34;&gt;om/IRenderState&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render-state&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:keys&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;comm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]}]&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/div&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt;
                   &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/input&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;js&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:type&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;
                                   &lt;span class=&#34;ss&#34;&gt;:ref&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;
                                   &lt;span class=&#34;ss&#34;&gt;:value&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                   &lt;span class=&#34;ss&#34;&gt;:onChange&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;put!&lt;/span&gt;
                                                &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:string&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;comm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                                &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/get-node&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                                    &lt;span class=&#34;nv&#34;&gt;.-value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))})&lt;/span&gt;

                   &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/div&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We&amp;rsquo;ve changed our widget to satisfy a few more Om interfaces that take
advantage of the &lt;a href=&#34;http://facebook.github.io/react/docs/component-specs.html&#34;&gt;React life cycles&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first is &lt;code&gt;om/IInitState&lt;/code&gt; which sets up some initial, local state for the
component. Here we are creating a map with a channel assigned to the &lt;code&gt;:string&lt;/code&gt;
key. &lt;code&gt;init-state&lt;/code&gt; is called once on a component.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;om/IWillMount&lt;/code&gt;, we setup a go loop that blocks on the channel assigned to
&lt;code&gt;:string&lt;/code&gt; earlier, then sets the &lt;code&gt;:text&lt;/code&gt; attribute in our application state to
the value we get off of that channel. Once it&amp;rsquo;s done it goes back to waiting on
the channel.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you&amp;rsquo;re new to Clojure, then the destructuring we do in the &lt;code&gt;let&lt;/code&gt; binding can
be a little confusing. The gist of what we&amp;rsquo;re doing is creating a local
&lt;code&gt;string&lt;/code&gt; variable for our go block that is based on a key in the map returned by
&lt;code&gt;(om/get-state owner :comm)&lt;/code&gt;. In other words, it takes the map we created
earlier and creates a local variable that is assigned the value of the
&lt;code&gt;:string&lt;/code&gt; key.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We use &lt;code&gt;om/transact!&lt;/code&gt; here since updating an atom needs to occur within a
transaction. We could have also used &lt;code&gt;swap!&lt;/code&gt; here to modify the &lt;code&gt;atom&lt;/code&gt; manually.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;will-mount&lt;/code&gt; is called once, before the component is mounted into the DOM.&lt;/p&gt;

&lt;p&gt;Finally, we&amp;rsquo;ve changed &lt;code&gt;om/IRender&lt;/code&gt; to &lt;code&gt;om/IRenderState&lt;/code&gt;. Every component needs
to satisfy one of these interfaces, but not both. The difference between the two
is that &lt;code&gt;IRenderState&lt;/code&gt; is passed the component state as it&amp;rsquo;s second argument. We
need it so that we can have access to the channel we created earlier.&lt;/p&gt;

&lt;p&gt;Finally we create the &lt;code&gt;input&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/input&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;js&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:type&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:ref&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:value&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:onChange&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;put!&lt;/span&gt;
                                &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:string&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;comm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/get-node&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                    &lt;span class=&#34;nv&#34;&gt;.-value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The element is actually only taking a single argument, though it looks like two.
&lt;code&gt;#js&lt;/code&gt; is a reader literal for Clojurscript that transforms the following object
into literal JavaScript object. The map that we pass is setting some attributes
on the component. In this case, we want a text input that contains the value of
the &lt;code&gt;:text&lt;/code&gt; key from our application state. We assign it the ref &lt;code&gt;text&lt;/code&gt; so that
we can refer to it from the &lt;code&gt;onChange&lt;/code&gt; callback via &lt;code&gt;om/get-node&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This callback is really simple, and is one of the reasons why core.async is so
attractive. All it does is take the value of the &lt;code&gt;text&lt;/code&gt; node and put it onto the
&lt;code&gt;string&lt;/code&gt; channel.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;ve been following along, then you should see the following:&lt;/p&gt;

&lt;div class=&#39;highlight example&#39; id=&#34;ex2&#34;&gt; &lt;/div&gt;

&lt;p&gt;The next step is to add in the text-size slider. First, let&amp;rsquo;s add the size to
our application state:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;app-state&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;atom&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Some Text&amp;quot;&lt;/span&gt;
                          &lt;span class=&#34;ss&#34;&gt;:size&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Next we&amp;rsquo;ll create another channel for manipulating this size:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;om/IInitState&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;init-state&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:comm&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:string&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;chan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
              &lt;span class=&#34;ss&#34;&gt;:size&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;chan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We&amp;rsquo;ll create another go block to update &lt;code&gt;:size&lt;/code&gt; whenever we get a value off of
this channel:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;om/IWillMount&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;will-mount&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:keys&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;comm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/get-state&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:comm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;go&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;
              &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/transact!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;fn &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;go&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;
              &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/transact!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:size&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;fn &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And then we&amp;rsquo;ll add the input. Since we&amp;rsquo;re getting the value off in the input
in a similar way as before, I created a small helper to do this. I would place
this function at the top of your source file, underneath the atom:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;get-value&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;-&amp;gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/get-node&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
          &lt;span class=&#34;nv&#34;&gt;.-value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/div&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/input&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;js&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:type&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;range&amp;quot;&lt;/span&gt;
                            &lt;span class=&#34;ss&#34;&gt;:min&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;
                            &lt;span class=&#34;ss&#34;&gt;:max&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;50&lt;/span&gt;
                            &lt;span class=&#34;ss&#34;&gt;:step&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.2&lt;/span&gt;
                            &lt;span class=&#34;ss&#34;&gt;:ref&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;size&amp;quot;&lt;/span&gt;
                            &lt;span class=&#34;ss&#34;&gt;:value&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:size&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                            &lt;span class=&#34;ss&#34;&gt;:onChange&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;put!&lt;/span&gt;
                                        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:size&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;comm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get-value&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;size&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))})&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/label&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:size&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;px&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note that you may want to update the text input as well.&lt;/p&gt;

&lt;p&gt;Finally, we want to modify our &lt;code&gt;div&lt;/code&gt; to have it&amp;rsquo;s font-size restyled whenever
this changes. Right now it looks like this:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/div&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Change it to this:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/div&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;js&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:style&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;js&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:font-size&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:size&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;px&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}}&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Again, &lt;code&gt;#js&lt;/code&gt; turns the following object into a JavaScript object. It&amp;rsquo;s shallow,
so we need to do it twice to set &lt;code&gt;:style&lt;/code&gt; correctly.&lt;/p&gt;

&lt;p&gt;You should see this now:&lt;/p&gt;

&lt;div class=&#39;highlight example&#39; id=&#34;ex3&#34;&gt; &lt;/div&gt;

&lt;p&gt;Now for the color sliders. First, we&amp;rsquo;ll add in the new state:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;app-state&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;atom&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Some Text&amp;quot;&lt;/span&gt;
                          &lt;span class=&#34;ss&#34;&gt;:size&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt;
                          &lt;span class=&#34;ss&#34;&gt;:colors&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:red&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
                                   &lt;span class=&#34;ss&#34;&gt;:green&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
                                   &lt;span class=&#34;ss&#34;&gt;:blue&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;As in the React widget, we&amp;rsquo;ll create a more general &lt;code&gt;color-slider&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;color-slider&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;colors&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:keys&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;label&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;onChange&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;color-key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]}]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;reify&lt;/span&gt;
        &lt;span class=&#34;nv&#34;&gt;om/IRenderState&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render-state&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:keys&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;comm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]}]&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/div&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt;
                   &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/input&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;js&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:type&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;range&amp;quot;&lt;/span&gt;
                                   &lt;span class=&#34;ss&#34;&gt;:min&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
                                   &lt;span class=&#34;ss&#34;&gt;:max&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;255&lt;/span&gt;
                                   &lt;span class=&#34;ss&#34;&gt;:step&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
                                   &lt;span class=&#34;ss&#34;&gt;:ref&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;color&amp;quot;&lt;/span&gt;
                                   &lt;span class=&#34;ss&#34;&gt;:value&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;color-key&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;colors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                                   &lt;span class=&#34;ss&#34;&gt;:onChange&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;onChange&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;color-key&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)})&lt;/span&gt;
                   &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/label&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;label&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;: &amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;color-key&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;colors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The important bit here is extra map of attributes we&amp;rsquo;ll be passing to this
component. We&amp;rsquo;re going to give it a label, a color key to pull from the
application state, and an onChange function.&lt;/p&gt;

&lt;p&gt;Next we&amp;rsquo;ll create a channel for the changing colors:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;nv&#34;&gt;om/IInitState&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;init-state&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:comm&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:string&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;chan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
              &lt;span class=&#34;ss&#34;&gt;:size&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;chan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
              &lt;span class=&#34;ss&#34;&gt;:colors&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;chan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And a go block:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;go&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;colors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/update!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;assoc-in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:colors&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;This looks slightly different than the previous go blocks because we&amp;rsquo;re dealing
with a map of colors in the application state instead of a straight value.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;putfn&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;fn &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;k&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                 &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;put!&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:colors&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;comm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;k&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get-value&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;o&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;color&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]))]&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;apply &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;dom/div&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt;
             &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;fn &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;label&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;color-key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/build&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;color-slider&lt;/span&gt;
                              &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:colors&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                              &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:label&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;label&lt;/span&gt;
                                      &lt;span class=&#34;ss&#34;&gt;:color-key&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;color-key&lt;/span&gt;
                                      &lt;span class=&#34;ss&#34;&gt;:onChange&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;putfn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}}))&lt;/span&gt;
                  &lt;span class=&#34;p&#34;&gt;[[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Red&amp;quot;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:red&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Green&amp;quot;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:green&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Blue&amp;quot;&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:blue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]])))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Next we&amp;rsquo;ll add the inputs right below the text size slider. We use some
high level functions here to avoid having to write three calls to &lt;code&gt;om/build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally we can modify the &lt;code&gt;div&lt;/code&gt; to re-color our text:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:size&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
          &lt;span class=&#34;nv&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:text&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:keys&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;red&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;green&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;blue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]}&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:colors&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
     &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/div&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;js&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:style&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;js&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:font-size&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;px&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                               &lt;span class=&#34;ss&#34;&gt;:color&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;rgb(&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;red&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;,&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;green&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;,&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;blue&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}}&lt;/span&gt;
              &lt;span class=&#34;nv&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here is the final product, for the second time:
&lt;div class=&#39;highlight example&#39; id=&#34;final&#34;&gt; &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;The full source for this example can be found &lt;a href=&#34;https://gist.github.com/mcramm/8755952&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Om is still very new, and changing rapidly. If you&amp;rsquo;re interested, then I
recommend running through the
&lt;a href=&#34;https://github.com/swannodette/om/wiki/Tutorial&#34;&gt;Tutorial&lt;/a&gt; in LightTable.&lt;/p&gt;

&lt;script src=&#34;http://mcramm.com/js/om-intro.js&#34; type=&#34;text/javascript&#34;&gt;&lt;/script&gt;</description>
    </item>
    
    <item>
      <title>React Intro</title>
      <link>http://mcramm.com/post/react-intro/</link>
      <pubDate>Sun, 26 Jan 2014 18:04:47 -0600</pubDate>
      
      <guid>http://mcramm.com/post/react-intro/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://facebook.github.io/react/&#34;&gt;React&lt;/a&gt; is a new-ish library from
Facebook/Instagram that is designed to make building user interfaces easy.&lt;/p&gt;

&lt;p&gt;I thought it would be fun to build a basic example in React, and then contrast
it with the same example in Om.&lt;/p&gt;

&lt;p&gt;First let&amp;rsquo;s setup the page where our example will live. We&amp;rsquo;re going to want a
container for the React root component, which we&amp;rsquo;ll give the id &lt;code&gt;app&lt;/code&gt;, and we&amp;rsquo;ll
include the React library and the JSX transformer.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;app&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;http://fb.me/react-0.8.0.js&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;http://fb.me/JSXTransformer-0.8.0.js&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;text/jsx&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&#34;cm&#34;&gt;/**&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;                * @jsx React.DOM&lt;/span&gt;
&lt;span class=&#34;cm&#34;&gt;                */&lt;/span&gt;
                &lt;span class=&#34;c1&#34;&gt;// Your code goes here&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note the &lt;code&gt;@jsx React.DOM&lt;/code&gt; in the block comment at the top of the script tag
where our code will go. This is required for the JSX transformer to be able to
process elements in our components from this:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;href&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;http://google.com&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Click Me&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Into this:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    React.DOM.a( {href:&amp;quot;http://google.com&amp;quot;}, &amp;quot;Click Me&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;JSX is completely optional, but it is a little bit easier to visualize the
arrangement of nodes, so I&amp;rsquo;ll be using it for this example.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s start writing some code. Our first goal is to create a text input
where any entered text is rendered out to some node.&lt;/p&gt;

&lt;p&gt;First we&amp;rsquo;ll create our root component and pass it some initial state:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    var VariableText = React.createClass({
        render: function() {
            return (
                &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;{this.props.defaultText}&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            );
        }
    });
    React.renderComponent(
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;VariableText&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;defaultText&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Some text&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;,
        document.getElementById(&amp;#39;app&amp;#39;)
    );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;What we&amp;rsquo;re doing here is create a component called &lt;code&gt;VariableText&lt;/code&gt; that knows how
to render itself. &lt;code&gt;render&lt;/code&gt; simply creates a &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag and inserts
&lt;code&gt;defaultText&lt;/code&gt; inside of it. The second argument to &lt;code&gt;renderComponent&lt;/code&gt; is simply
explaining where to insert our component on our page.&lt;/p&gt;

&lt;p&gt;This is great, but kinda boring. Let&amp;rsquo;s create our text input and change the
content of the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag when we type into it. This next snippet will be a
little bit bigger, but all we really want to do is create a &lt;code&gt;TextInput&lt;/code&gt;
component that renders an &lt;code&gt;input&lt;/code&gt; tag and responds to changes. We&amp;rsquo;ll also want
to pass it our default text to set the input&amp;rsquo;s initial value.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    var TextInput = React.createClass({
        handleChange: function() {
            var text = this.refs.text.getDOMNode().value;
            this.props.onTextChanged(text);
            return false;
        },
        render: function() {
            return (
                &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;ref&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;onChange&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.handleChange}&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;text&amp;#39;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.props.inputValue}&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            );
        }
    });

    var VariableText = React.createClass({
        getInitialState: function() {
            return {
                text: this.props.defaultText
           }
        },
        handleTextChange: function(text) {
            this.setState({text: text});
        },
        render: function() {
            return (
                &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;TextInput&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;onTextChanged&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.handleTextChange}&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;inputValue&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.state.text}&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;{this.state.text}&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            );
        }
    });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We&amp;rsquo;ve had to change our &lt;code&gt;VariableText&lt;/code&gt; component since we&amp;rsquo;ll need to introduce
some mutable state, the value of the text input, into our app. The
&lt;code&gt;getInitialState&lt;/code&gt; function is called once, before the component is mounted. The
return value of this function will set the initial value of the &lt;code&gt;state&lt;/code&gt; attribute for
this component. Here we&amp;rsquo;re setting it to the default text property. &lt;code&gt;VariableText&lt;/code&gt;
is going to be our root component, and will coordinate any state changes based
on events triggered on its children.&lt;/p&gt;

&lt;p&gt;Our first child component is &lt;code&gt;TextInput&lt;/code&gt;. As mentioned before this component
renders an input tag and calls the component&amp;rsquo;s &lt;code&gt;handleChange&lt;/code&gt; function whenever
the value changes. &lt;code&gt;handleChange&lt;/code&gt; gets the value from the input via the &lt;code&gt;refs&lt;/code&gt;
attribute. When we create components in &lt;code&gt;render&lt;/code&gt;, we can attach a special
property &lt;code&gt;ref&lt;/code&gt; to it that lets us refer back to it later. Once we get the value, we
execute a callback that was assigned in our root component. This is the typical
way a child communicates with its parent, and we&amp;rsquo;ll see this pattern occur
throughout the rest of the example.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;re following along on your own, this is what you should have so far:
&lt;div class=&#39;highlight example&#39; id=&#34;ex1&#34;&gt; &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Now let&amp;rsquo;s introduce a slider to change the font size of our output text. We&amp;rsquo;ll
create a &lt;code&gt;FontSizeSlider&lt;/code&gt; component that again renders an &lt;code&gt;input&lt;/code&gt; tag.
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    var FontSizeSlider = React.createClass({
        handleChange: function() {
            var value = this.refs.slider.getDOMNode().value;
            this.props.onSliderChanged(value);
            return false;
        },
        render: function() {
            return (
                &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;ref&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;slider&amp;quot;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;onChange&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.handleChange}&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.props.size}&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;range&amp;#39;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;min&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;9&amp;quot;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;50&amp;quot;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;step&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;0.2&amp;quot;&lt;/span&gt; 
                    &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; Font Size: {this.props.size} &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;span&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            );
        }
    });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

This should look very similar to the &lt;code&gt;TextInput&lt;/code&gt; component. Here is what changed
on &lt;code&gt;VariableText&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    getInitialState: function() {
        return {
            size: this.props.defaultSize,
            text: this.props.defaultText,
        }
    },
    handleFontSizeChange: function(size) {
        this.setState({size: size});
        this.refs.outputText.getDOMNode().style.fontSize = size + &amp;quot;px&amp;quot;;
    },
    render: function() {
        return (
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;TextInput&lt;/span&gt;
                    &lt;span class=&#34;na&#34;&gt;onTextChanged&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.handleTextChange}&lt;/span&gt;
                    &lt;span class=&#34;na&#34;&gt;inputValue&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.state.text}&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;FontSizeSlider&lt;/span&gt;
                    &lt;span class=&#34;na&#34;&gt;onSliderChanged&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.handleFontSizeChange}&lt;/span&gt;
                    &lt;span class=&#34;na&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.state.size}&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;ref&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;outputText&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;{this.state.text}&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        );
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

Again this should look similar to the previous change. All we&amp;rsquo;ve done is add
another child component and react to it changing it the same way as &lt;code&gt;TextInput&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;defaultSize&lt;/code&gt; prop will also need to be passed into the root component:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;VariableText&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;defaultText&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Some text&amp;quot;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;defaultSize&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{15}/&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;You should now see something like the following:
&lt;div class=&#39;highlight example&#39; id=&#34;ex2&#34;&gt; &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s create a few more sliders and see how React gives you the
ability to reduce code duplication. These sliders will control the red, green,
and blue levels of our output text.&lt;/p&gt;

&lt;p&gt;Since these sliders will respond to change similarly to our &lt;code&gt;FontSizeSlider&lt;/code&gt;
component, we&amp;rsquo;ll create a mixin:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    var HandleSliderChangeMixin = {
        handleChange: function() {
            var value = this.refs.slider.getDOMNode().value;
            this.props.onSliderChanged(value);
            return false;
        }
    };
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Each of these color sliders will be pretty similar. They will all range from 0
to 255, and have a label to display its value. Let&amp;rsquo;s create a generic component
first:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    var FontColorSlider = React.createClass({
        mixins: [HandleSliderChangeMixin],
        render: function() {
            return (
                &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;ref&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;slider&amp;quot;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;onChange&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.handleChange}&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.props.value}&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#39;range&amp;#39;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;min&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;0&amp;quot;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;255&amp;quot;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;step&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;{this.props.label}: {this.props.value}&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;label&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            );
        }
    });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note that we use the &lt;code&gt;HandleSliderChangeMixin&lt;/code&gt; here. We&amp;rsquo;ll also want to update
&lt;code&gt;FontSizeSlider&lt;/code&gt; to use this mixin.&lt;/p&gt;

&lt;p&gt;Next we&amp;rsquo;ll create a component that will create a &lt;code&gt;FontColorSlider&lt;/code&gt; for each
color value and communicate to our root component with the new values.&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    var FontColorSliders = React.createClass({
        handleChange: function(r, g, b) {
            this.props.onColorsChanged({r: r, g: g, b: b});
        },
        handleRedChange: function(value) {
            this.handleChange(value, this.props.colors.g, this.props.colors.b);
        },
        handleGreenChange: function(value) {
            this.handleChange(this.props.colors.r, value, this.props.colors.b);
        },
        handleBlueChange: function(value) {
            this.handleChange(this.props.colors.r, this.props.colors.g, value);
        },
        render: function() {
            return (
                &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;FontColorSlider&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;onSliderChanged&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.handleRedChange}&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;label&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Red&amp;quot;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.props.colors.r}&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;FontColorSlider&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;onSliderChanged&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.handleGreenChange}&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;label&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Green&amp;quot;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.props.colors.g}&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;FontColorSlider&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;onSliderChanged&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.handleBlueChange}&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;label&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;Blue&amp;quot;&lt;/span&gt;
                        &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.props.colors.b}&lt;/span&gt;
                    &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            );
        }
    });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here are the changes to &lt;code&gt;VariableText&lt;/code&gt; that we&amp;rsquo;ll need to make:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    getInitialState: function() {
        return {
            size: this.props.defaultSize,
            text: this.props.defaultText,
            colors: {r:0, g:0, b:0}
        }
    },
    colorsToRGB: function(colors) {
        return &amp;quot;rgb(&amp;quot; + colors.r + &amp;quot;,&amp;quot; + colors.g + &amp;quot;,&amp;quot; + colors.b + &amp;quot;)&amp;quot;;
    },
    handleColorsChange: function(colors) {
        this.setState({colors: colors});
        this.refs.outputText.getDOMNode().style.color = this.colorsToRGB(colors);
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;Don&amp;rsquo;t forget to add our new component to the &lt;code&gt;render&lt;/code&gt; method:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;FontColorSliders&lt;/span&gt;
        &lt;span class=&#34;na&#34;&gt;onColorsChanged&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.handleColorsChange}&lt;/span&gt;
        &lt;span class=&#34;na&#34;&gt;colors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;{this.state.colors}&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;Here is the final product:
&lt;div class=&#39;highlight example&#39; id=&#34;ex3&#34;&gt; &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;The full source for this example can be found &lt;a href=&#34;https://gist.github.com/mcramm/8636822&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Most of this should be pretty straight forward. Again, the goal here was to
create something simple to get your feet wet with. There are a few opportunities
to make things even simpler, but I&amp;rsquo;ll leave that as an exercise for the reader.&lt;/p&gt;

&lt;p&gt;If you plan on exploring more of React, then I recommend going through
their &lt;a href=&#34;http://facebook.github.io/react/docs/tutorial.html&#34;&gt;tutorial&lt;/a&gt;, and
checking out the different &lt;a href=&#34;http://facebook.github.io/react/docs/component-specs.html&#34;&gt;life cycle methods&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In an upcoming post, I&amp;rsquo;ll be creating a similar app in &lt;a href=&#34;https://github.com/swannodette/om&#34;&gt;Om&lt;/a&gt;.&lt;/p&gt;

&lt;script src=&#34;https://fb.me/react-0.13.3.min.js&#34;&gt;&lt;/script&gt;
&lt;script src=&#34;http://mcramm.com/js/react_intro/build/ex1.js&#34;&gt;&lt;/script&gt;
&lt;script src=&#34;http://mcramm.com/js/react_intro/build/ex2.js&#34;&gt;&lt;/script&gt;
&lt;script src=&#34;http://mcramm.com/js/react_intro/build/ex3.js&#34;&gt;&lt;/script&gt;
</description>
    </item>
    
    <item>
      <title>Leiningen Templates</title>
      <link>http://mcramm.com/post/leiningen-templates/</link>
      <pubDate>Mon, 06 Jan 2014 18:04:47 -0600</pubDate>
      
      <guid>http://mcramm.com/post/leiningen-templates/</guid>
      <description>&lt;p&gt;Getting started with Clojurescript can be tough if you&amp;rsquo;ve never done it before,
and once you do you might find yourself running through the same steps to get
new projects into a structure that makes sense. In either case, the solution is
to use a Leiningen template. My goal here is to show how easy it can be
to create one of your own. Most templates are built for Clojure, but we&amp;rsquo;ll
be creating one for Clojurescript. On top of that we&amp;rsquo;ll get ourselves started
off with the new Om library.&lt;/p&gt;

&lt;p&gt;Before beginning I want to make it clear that this isn&amp;rsquo;t meant as an
introduction to Clojurescript, &lt;a href=&#34;https://github.com/swannodette/om&#34;&gt;Om&lt;/a&gt;, or the framework it acts as an interface to
(&lt;a href=&#34;http://facebook.github.io/react/&#34;&gt;React&lt;/a&gt;). This is meant to help you through creating a Leiningen template that
will get you going quickly on a new project. If you want a bare-bones template
for a new Clojurescript project, then I recommend &lt;a href=&#34;https://clojars.org/mies/lein-template&#34;&gt;mies&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using Leiningen you can create new templates with a default project structure
through the &lt;code&gt;new&lt;/code&gt; task: &lt;code&gt;lein new &amp;lt;template&amp;gt; &amp;lt;name&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s create one together. Since we&amp;rsquo;re creating one for the Om library, we&amp;rsquo;ll
call it &amp;lsquo;Hum&amp;rsquo;:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span&gt;&lt;/span&gt;    lein new template hum
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;To install this template locally, &lt;code&gt;cd&lt;/code&gt; into it and run &lt;code&gt;lein install&lt;/code&gt;. Let&amp;rsquo;s see
what a project based off this bare template looks like. Run &lt;code&gt;lein new hum my-app&lt;/code&gt;.
You should get a directory tree with one file like this:
&lt;code&gt;my-app/src/my_app/foo.clj&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The contents of this file should simply be &lt;code&gt;(def my-app :foo)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Open up &lt;code&gt;src/leiningen/new/hum.clj&lt;/code&gt; and look at the &lt;code&gt;hum&lt;/code&gt; function:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;hum&lt;/span&gt;
      &lt;span class=&#34;s&#34;&gt;&amp;quot;FIXME: write documentation&amp;quot;&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;
                  &lt;span class=&#34;ss&#34;&gt;:sanitized&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;name-to-path&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}]&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main/info&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Generating fresh &amp;#39;lein new&amp;#39; hum project.&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;-&amp;gt;files&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;
                 &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;src/{{site.lcbs}}sanitized{{site.rcbs}}/foo.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;foo.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)])))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let&amp;rsquo;s go through this line by line.  This function takes a name then creates a
map, &lt;code&gt;data&lt;/code&gt;, that contains this name and a sanitized version of it.  &lt;code&gt;name-to-path&lt;/code&gt;
simply takes a name and first replaces any dashes with underscores, then any
periods with directory separators.  So a name like &lt;code&gt;lawrence-of.arabia&lt;/code&gt;
becomes &lt;code&gt;lawrence_of/arabia&lt;/code&gt;. For us, &lt;code&gt;hum&lt;/code&gt; will remain unchanged.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;main/info&lt;/code&gt; line is simply printing some info to the user.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-&amp;gt;files&lt;/code&gt; is where the action happens. This function takes a map containing at
least the key &lt;code&gt;name&lt;/code&gt; and a variable number of &amp;ldquo;paths&amp;rdquo;. Each path is a vector
containing a string representing the path to a file, and some
content for that file.&lt;/p&gt;

&lt;p&gt;To understand the &lt;code&gt;render&lt;/code&gt; call a little better, we need to look at the
definition right above this function:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;renderer&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;hum&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;All this does is create a renderer that will process one of our templates and
replace the appropriate variables. This templating is based off of mustache
which you&amp;rsquo;ll see in a moment. For now, all you need to know is that &lt;code&gt;render&lt;/code&gt;
will take the name of a file in &lt;code&gt;src/leiningen/new/hum&lt;/code&gt; and replaces certain
areas that we specify with our supplied &lt;code&gt;data&lt;/code&gt;. If we don&amp;rsquo;t supply any data
then the file remains unchanged.&lt;/p&gt;

&lt;p&gt;Keeping with our example, using this line:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;src/{{site.lcbs}}sanitized{{site.rcbs}}/foo.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;foo.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;Will create a file at &lt;code&gt;src/hum/foo.clj&lt;/code&gt; with the content of the file &lt;code&gt;foo.clj&lt;/code&gt;.
Let&amp;rsquo;s open that file up and see this templating in action:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;site.lcbs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;site.rcbs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}}&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:foo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Remember that the &lt;code&gt;:name&lt;/code&gt; key in &lt;code&gt;data&lt;/code&gt; is set the unsanitized value we supply.&lt;/p&gt;

&lt;p&gt;Now lets start making some changes. Create a file at
&lt;code&gt;src/leiningen/new/hum/project.clj&lt;/code&gt; and give it the following content:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defproject &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;site.lcbs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;site.rcbs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}}&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;0.1.0-SNAPSHOT&amp;quot;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;:description&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;FIXME: write this!&amp;quot;&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;:url&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;http://example.com/FIXME&amp;quot;&lt;/span&gt;

      &lt;span class=&#34;ss&#34;&gt;:dependencies&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;org.clojure/clojure&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;1.5.1&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                     &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;org.clojure/clojurescript&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;0.0-2138&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                     &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;om&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;0.1.4&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;

      &lt;span class=&#34;ss&#34;&gt;:plugins&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;lein-cljsbuild&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;1.0.1&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]]&lt;/span&gt;

      &lt;span class=&#34;ss&#34;&gt;:cljsbuild&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
        &lt;span class=&#34;ss&#34;&gt;:builds&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;dev&amp;quot;&lt;/span&gt;
                  &lt;span class=&#34;ss&#34;&gt;:source-paths&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;src&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                  &lt;span class=&#34;ss&#34;&gt;:compiler&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:output-to&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;{{site.lcbs}}sanitized{{site.rcbs}}.js&amp;quot;&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:output-dir&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;out&amp;quot;&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:optimizations&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:none&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:source-map&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;
                    &lt;span class=&#34;ss&#34;&gt;:externs&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;om/externs/react.js&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]}}]})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This is doing a bunch of stuff, but is a reasonably standard starting point. The
main differences is that I&amp;rsquo;ve included the Om library as a dependency.&lt;/p&gt;

&lt;p&gt;Now add this to the list of processed files in &lt;code&gt;hum.clj&lt;/code&gt;:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;-&amp;gt;files&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;
             &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;project.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;project.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
             &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;src/{{site.lcbs}}sanitized{{site.rcbs}}/foo.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;foo.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)])))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;To test it out, run &lt;code&gt;lein new hum my-app&lt;/code&gt;. Remember to remove the previous test
first, and make sure you are in the root of the template project. Open up
&lt;code&gt;my-app/project.clj&lt;/code&gt; and marvel at the magic.&lt;/p&gt;

&lt;p&gt;There are few more things we need to add to finish this off. First let&amp;rsquo;s get rid
of &lt;code&gt;foo.clj&lt;/code&gt; by renaming it to a Clojurescript file, like &lt;code&gt;core.cljs&lt;/code&gt;.
Change the content of the file to this:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;site.lcbs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{{&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;site.rcbs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;.core&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:require&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;om.core&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;om&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:include-macros&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
                &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;om.dom&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:as&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;dom&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:include-macros&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;enable-console-print!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;app-state&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;atom&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:clicks&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;button&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/component&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/div&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;nil&lt;/span&gt;
                 &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/button&lt;/span&gt;
                   &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;js&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:onClick&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/transact!&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:clicks&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;inc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}&lt;/span&gt;
                   &lt;span class=&#34;s&#34;&gt;&amp;quot;Click Me&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
                 &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;dom/span&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;js&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:clicks&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;my-app&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;owner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;reify&lt;/span&gt;
        &lt;span class=&#34;nv&#34;&gt;om/IRender&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/build&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;button&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}))))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;om/root&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;app-state&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;my-app&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;js/document.body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Again the intent here is not to introduce you to Om, or Clojurescript. All
you need to know for now is that this creates a button and counter that tracks how
many times the button has been clicked.&lt;/p&gt;

&lt;p&gt;Your list of processed files should look something like this:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;project.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;project.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;src/{{site.lcbs}}sanitized{{site.rcbs}}/core.cljs&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;core.cljs&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let&amp;rsquo;s add in one more file, &lt;code&gt;index.html&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;http://fb.me/react-0.8.0.js&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;out/goog/base.js&amp;quot;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;{{site.lcbs}}sanitized{{site.rcbs}}.js&amp;quot;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;goog&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;quot;{{site.lcbs}}sanitized{{site.rcbs}}.core&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And to the list of processed files:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;index.html&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;index.html&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;project.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;project.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;src/{{site.lcbs}}sanitized{{site.rcbs}}/core.cljs&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;core.cljs&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The full &lt;code&gt;hum&lt;/code&gt; function should look similar to this:&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defn &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;hum&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;let &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;
                  &lt;span class=&#34;ss&#34;&gt;:sanitized&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;name-to-path&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)}]&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main/info&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;Generating a new Om project using the Hum template&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;-&amp;gt;files&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;
                 &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;index.html&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;index.html&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
                 &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;project.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;project.clj&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
                 &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;src/{{site.lcbs}}sanitized{{site.rcbs}}/core.cljs&amp;quot;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;core.cljs&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)])))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now we&amp;rsquo;re done. Run &lt;code&gt;lein new hum my-app&lt;/code&gt; again and &lt;code&gt;cd&lt;/code&gt; into it. Run &lt;code&gt;lein deps&lt;/code&gt;
to get any dependencies, then &lt;code&gt;lein cljsbuild once dev&lt;/code&gt;. Open up &lt;code&gt;index.html&lt;/code&gt;
and voila! You should see something like the following:&lt;/p&gt;

&lt;div class=&#39;highlight example&#39; id=&#34;lein-templates-example&#34;&gt; &lt;/div&gt;

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

&lt;p&gt;If you&amp;rsquo;re looking for more about creating templates, then I recommend the
excellent &lt;a href=&#34;https://github.com/technomancy/leiningen/blob/stable/doc/TEMPLATES.md&#34;&gt;Leiningen
docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The full source for this template can be found
&lt;a href=&#34;https://github.com/mcramm/hum&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;script src=&#34;http://mcramm.com/js/lein-templates.js&#34;&gt;&lt;/script&gt;
</description>
    </item>
    
    <item>
      <title>Specificity in ClojureScript</title>
      <link>http://mcramm.com/post/specificity-in-clojurescript/</link>
      <pubDate>Thu, 02 Jan 2014 18:04:47 -0600</pubDate>
      
      <guid>http://mcramm.com/post/specificity-in-clojurescript/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com/clojure/clojurescript/commit/571e156d2daa223dcef273106827e932283e2f93&#34;&gt;This commit&lt;/a&gt; was pushed up to Clojurescript core recently, adding a new
macro &lt;code&gt;specify&lt;/code&gt;. This means we can now have instance-level implementations of
protocols on specific values:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre&gt;&lt;code class=&#34;language-clojure&#34; data-lang=&#34;clojure&#34;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;ns &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;example1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;enable-console-print!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;defprotocol &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;Listable&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;


    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;def &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elements&lt;/span&gt;
     &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;specify&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;one&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;two&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;three&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
       &lt;span class=&#34;nv&#34;&gt;Listable&lt;/span&gt;
       &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
         &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;str&lt;/span&gt;
           &lt;span class=&#34;s&#34;&gt;&amp;quot;&amp;lt;ul&amp;gt;&amp;quot;&lt;/span&gt;
           &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;apply str &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;map &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;str &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;&amp;lt;li&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
           &lt;span class=&#34;s&#34;&gt;&amp;quot;&amp;lt;/ul&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;println &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;satisfies?&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;Listable&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;elements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;; true&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;println &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;satisfies?&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;Listable&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;one&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;two&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;three&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;; false&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;; false&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;println &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;elements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;; &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;one&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;two&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;three&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;println &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elements&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;; [one two three]&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;println &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;= &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elements&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;one&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;two&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;three&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;; true&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;println &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;identical? &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;elements&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;quot;one&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;two&amp;quot;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;quot;three&amp;quot;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]))&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;; false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This is pretty important feature for Clojurescript. &lt;code&gt;extend-type&lt;/code&gt; is still
powerful, but there is the odd time where you want to make a specific value
conform to an interface. Because we&amp;rsquo;re on Javascript, we can get this level of
modularity without a huge performance cost.&lt;/p&gt;

&lt;p&gt;Note that this relies on version &lt;code&gt;0.0-2138&lt;/code&gt; of Clojurescript.&lt;/p&gt;

&lt;p&gt;This change was authored by the indomitable &lt;a href=&#34;http://swannodette.github.io/&#34;&gt;David Nolen&lt;/a&gt; whose &lt;a href=&#34;https://github.com/swannodette/om&#34;&gt;latest open source offering&lt;/a&gt; in a Clojurescript interface over Facebook&amp;rsquo;s &lt;a href=&#34;http://facebook.github.io/react/&#34;&gt;React&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title></title>
      <link>http://mcramm.com/projects/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>http://mcramm.com/projects/</guid>
      <description></description>
    </item>
    
  </channel>
</rss>