<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;A0MBQn08cSp7ImA9WhRXEE4.&quot;"><id>tag:blogger.com,1999:blog-10486307</id><updated>2011-12-16T13:44:13.379+01:00</updated><category term="reading" /><category term="jfokus" /><category term="meltingspot" /><category term="java" /><category term="clojure" /><category term="citerus" /><category term="spam" /><category term="development" /><category term="music" /><category term="development reading" /><category term="DDD" /><category term="code" /><category term="psa" /><title>The Weak Reference</title><subtitle type="html">A blog on software development, and other extremely interesting things.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://weakreference.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>67</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/TheWeakReference" /><feedburner:info uri="theweakreference" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;D0ANSX48cSp7ImA9Wx9WEUU.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-5992800862475221192</id><published>2011-01-16T14:42:00.002+01:00</published><updated>2011-01-16T14:49:58.079+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-16T14:49:58.079+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="jfokus" /><category scheme="http://www.blogger.com/atom/ns#" term="DDD" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="spam" /><title>Jfokus 2011</title><content type="html">&lt;a href="http://www.jfokus.se/"&gt;Jfokus 2011&lt;/a&gt; is getting closer and this year looks fantastic! New venue, an additional day, and, as always, many interesting speakers. &lt;a href="http://www.jfokus.se/jfokus/page.jsp?id=schema_day1"&gt;Tuesday February 15&lt;/a&gt; has a DDD track with lots of great speakers, including Eric Evans.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.citerus.se/"&gt;Citerus&lt;/a&gt; is of course represented as a Jfokus partner also this year. We will be in the exhibition both conference days, come and see us!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-5992800862475221192?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/MuoRquLTvyY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/5992800862475221192/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=5992800862475221192" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/5992800862475221192?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/5992800862475221192?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/MuoRquLTvyY/jfokus-2011.html" title="Jfokus 2011" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2011/01/jfokus-2011.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEENQng-eyp7ImA9Wx5SGEs.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-560981471502647771</id><published>2010-08-15T10:53:00.004+02:00</published><updated>2010-08-15T10:58:13.653+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-15T10:58:13.653+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DDD" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><title>DDD classes survey</title><content type="html">Eric Evans is doing a survey to guide future developments of the DDD classes that &lt;a href="http://www.citerus.se/"&gt;Citerus&lt;/a&gt; and other partners around the world offer together with &lt;a href="http://domainlanguage.com/"&gt;Domain Language&lt;/a&gt;. If you are interested in DDD training, please take a moment to complete the survey. Thanks!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://domainlanguage.com/survey/2010-08/"&gt;http://domainlanguage.com/survey/2010-08/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-560981471502647771?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/yXims0M55wM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/560981471502647771/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=560981471502647771" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/560981471502647771?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/560981471502647771?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/yXims0M55wM/ddd-classes-survey.html" title="DDD classes survey" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2010/08/ddd-classes-survey.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIAQXs5fyp7ImA9WxFWEE4.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-5357352366346400333</id><published>2010-05-28T10:59:00.004+02:00</published><updated>2010-05-28T11:05:40.527+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-28T11:05:40.527+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="music" /><category scheme="http://www.blogger.com/atom/ns#" term="meltingspot" /><title>Meltingspot #4</title><content type="html">&lt;a href="http://www.meltingspot.se/index.php/2010/05/25/4-this-was-meant-to-be/"&gt;Meltingspot #4&lt;/a&gt; is now available. This time we start off with Daft Punk and end with Coldplay, while visiting both The Knife and Kraftwerk on our way.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.meltingspot.se/index.php/2010/05/25/4-this-was-meant-to-be/"&gt;Meltingspot #4 - &lt;span style="font-style:italic;"&gt;This was meant to be&lt;/span&gt;&lt;/a&gt;, enjoy!&lt;br /&gt;&lt;br /&gt;Follow us on Twitter &lt;a href="http://www.twitter.com/meltingspot"&gt;@meltingspot&lt;/a&gt;, and stay tuned for our upcoming lists with music for the summer!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-5357352366346400333?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/ynPbUleh2dU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/5357352366346400333/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=5357352366346400333" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/5357352366346400333?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/5357352366346400333?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/ynPbUleh2dU/meltingspot-4.html" title="Meltingspot #4" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2010/05/meltingspot-4.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUESXY6eyp7ImA9WxFQEEw.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-601171766375439940</id><published>2010-05-04T23:35:00.008+02:00</published><updated>2010-05-05T00:30:08.813+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-05T00:30:08.813+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="development" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><title>Your Build, Lava Lamps and Clojure</title><content type="html">&lt;span style="font-style: italic;"&gt;Long time without a post, here's one that's long overdue!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After a Javaform JUG meet-up this fall I happened to talk with &lt;a href="http://www.twitter.com/matkar"&gt;@matkar&lt;/a&gt; (of &lt;a href="http://www.javaforum.se/"&gt;Javaforum&lt;/a&gt; and &lt;a href="http://www.jfokus.se/"&gt;Jfokus&lt;/a&gt; fame) at the pub following the meeting. He very convincingly described how great it is to use lava lamps as a visual tool for showing current build status. Actually, he pretty much insisted that I'd set it up immediately in my current project.&lt;br /&gt;&lt;br /&gt;Well, it did sound like fun, so I got started. This blog post will layout what you need and how to create your own lava lamp powered visual workspace!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The build&lt;/span&gt;&lt;br /&gt;First, you need a continuous integration (CI) server, also known as a  build server. Your project needs one of these anyway, so if you don't have one in place, this is definitely the first thing to take care of!&lt;br /&gt;&lt;br /&gt;In my current project we use Jetbrains TeamCity, but there are a number of free open-source products available as well.&lt;br /&gt;&lt;br /&gt;You also need a way to extract the relevant build status data from the CI server. Depending on product there are typically a number of different ways of doing this. I used the RSS feed facility of TeamCity and polled the project's Atom feed for build status with certain intervals. For more immediate notifications one could probably fairly easy use TeamCity's Jabber support instead. But this was the easiest thing to setup and use, so I went with that, configuring a RSS feed with status information for the relevant code branch.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Hardware&lt;/span&gt;&lt;br /&gt;Secondly, you will need some hardware. By tradition, lava lamps is the number one choice for signaling here, but one can easily think of other options as well. If you decide to go down the lava lamp light road, try to get something that has a short start-up time. The ones I used take about 1.5 h to warm up (i.e. until they start "bubbling"), which is kind of long. If you have a disciplined team, the broken build will be fixed long before that. I got my lights from the gadget shop &lt;a href="http://www.teknikmagasinet.se/"&gt;Teknikmagasinet&lt;/a&gt; here in Sweden, perhaps more expensive gear from a vendor like &lt;a href="http://www.mathmos.co.uk/"&gt;Mathmos&lt;/a&gt; would work better, but I don't know.&lt;br /&gt;&lt;br /&gt;Then, you need some way of controlling the lamps. I did this by using an USB controllable power strip. In particular I used the &lt;a href="http://www.gmb-online.nl/item_view.aspx?id=2755"&gt;SIS-PM Silver Shield Programmable Power Outlet Strip&lt;/a&gt;  which comes with a simple but surprisingly nice GUI for use with Windows computers to control which sockets are on and which are off. It also comes with a Windows command line utility, which was the integration point I decided to use. I do my development on a Mac but the lava lamp solution was deployed on a Windows machine, so this worked out nicely.&lt;br /&gt;&lt;br /&gt;For non-Windows deployment there are Linux drivers available for download from the page above, though I have not tried them out. There is also a &lt;a href="http://sispmctl.sourceforge.net/"&gt;SourceForge project&lt;/a&gt; with software for the power strip.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Software&lt;/span&gt;&lt;br /&gt;The final piece of the puzzle is the software that regularly polls the CI server's RSS feed and controls the power sockets according to current build status – successful or failed, in order to turn on and turn off the lights.&lt;br /&gt;&lt;br /&gt;The code is written in &lt;a href="http://www.clojure.org/"&gt;Clojure&lt;/a&gt;. It uses functionality from &lt;span style="font-family:Courier New;"&gt;clojure.contrib&lt;/span&gt; to parse the RSS XML and call the command line utility to control the power strip. The lightweight scheduling component &lt;a href="http://www.sauronsoftware.it/projects/cron4j/"&gt;cron4j&lt;/a&gt; is also used, which integrates very nicely with Clojure.&lt;br /&gt;&lt;br /&gt;The code and &lt;a href="http://github.com/technomancy/leiningen"&gt;Leiningen&lt;/a&gt; project definition file can be found &lt;a href="http://gist.github.com/388555"&gt;a this GitHub Gist&lt;/a&gt;. I use the Leiningen command &lt;span style="font-family:Courier New;"&gt;uberjar&lt;/span&gt; to create a runnable JAR, making deployment extremely simple. The code assumes that the two sockets used are named &lt;span style="font-family:Courier New;"&gt;green&lt;/span&gt; and &lt;span style="font-family:Courier New;"&gt;red&lt;/span&gt;, the strip itself must be named &lt;span style="font-family:Courier New;"&gt;lava&lt;/span&gt;. These names can be assigned using the GUI tool shipped with the power strip.&lt;br /&gt;&lt;br /&gt;As far as examples of functional programming goes this code is a particularly bad example. Functional programming is much about side-effect free pure functions and this use case is pretty much all about side-effects. But I think it shows rather nicely that Clojure can be used for all sorts of things, including problems like this, perhaps more suitable for script-type languages. Also, an obvious simplification that could be made is to avoid storing internal build state, and instead always update the lights according to the latest polled build-result, even in the case when nothing has changed.&lt;br /&gt;&lt;br /&gt;The program is configured through a settings file. This is a standard Java properties file specifying the path to the command tool and two cron expressions. The first cron expression describes when and how often to poll the build server, and the second specifies a time to shut it all down for the day so the lamps get the chance to recover a bit during night when the office is empty.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Bill Of Materials&lt;/span&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;CI server, &lt;a href="http://www.jetbrains.com/teamcity/"&gt;JetBrains TeamCity&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;One red and one green lava lamp (available in Sweden from &lt;a href="http://www.teknikmagasinet.com/"&gt;Teknikmagasinet&lt;/a&gt;)&lt;br /&gt;SIS-PM Silver Shield Programmable Power Outlet Strip (available in Sweden from &lt;a href="http://www.kjell.com/"&gt;Kjell &amp;amp; Co&lt;/a&gt;)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-601171766375439940?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/LIVVUdrURxU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/601171766375439940/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=601171766375439940" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/601171766375439940?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/601171766375439940?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/LIVVUdrURxU/your-build-lava-lamps-and-clojure.html" title="Your Build, Lava Lamps and Clojure" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2010/05/your-build-lava-lamps-and-clojure.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYARn04eip7ImA9WxBXGEs.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-8207153606576848665</id><published>2010-01-30T15:52:00.003+01:00</published><updated>2010-01-30T16:09:07.332+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-30T16:09:07.332+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="spam" /><category scheme="http://www.blogger.com/atom/ns#" term="music" /><title>Meltingspot</title><content type="html">Meltingspot is a side project I run together with &lt;a href="http://www.tobiashill.se/"&gt;Tobias Hill&lt;/a&gt;. We're both big music lovers and we thought it could be an interesting idea to share some of our current listening with other people. With the advent of &lt;a href="http://www.spotify.com/"&gt;Spotify&lt;/a&gt; these kind of collaborations has now become quite a lot easier. &lt;br /&gt;&lt;br /&gt;We will try to publish a new playlist regularly, perhaps once per month or so. Hopefully you will find something you like and we will get some great new listening tips in return. &lt;br /&gt;&lt;br /&gt;The playlists are published at &lt;a href="http://www.meltingspot.se/"&gt;http://www.meltingspot.se&lt;/a&gt;, you can also follow us on Twitter &lt;a href="http://www.twitter.com/meltingspot"&gt;@meltingspot&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.meltingspot.se/index.php/2010/01/29/2-box-in-shape-of-things-to-come/"&gt;Meltingspot #2 - Box in shape of things to come&lt;/a&gt;, is now live. Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-8207153606576848665?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/wycu9_SW0ZY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/8207153606576848665/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=8207153606576848665" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/8207153606576848665?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/8207153606576848665?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/wycu9_SW0ZY/meltingspot.html" title="Meltingspot" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2010/01/meltingspot.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEMQ307eCp7ImA9WxBQEEk.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-6326633704691823769</id><published>2010-01-09T14:35:00.003+01:00</published><updated>2010-01-09T14:44:42.300+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-09T14:44:42.300+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="jfokus" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><title>Speaking at Jfokus 2010</title><content type="html">I will be giving a short introduction to Clojure for Java developers at Jfokus 2010 conference day, January 27. &lt;br /&gt;&lt;br /&gt;The presentation will be in Swedish, more info on the &lt;a href="http://www.jfokus.se/jfokus/speakers.jsp#Patrik%20Fredriksson"&gt;Jfokus program page&lt;/a&gt; (in Swedish).&lt;br /&gt;&lt;br /&gt;Jfokus 2010 is now fully booked, but there is a &lt;a href="http://www.jfokus.se/jfokus/register.jsp"&gt;waiting list&lt;/a&gt; if more seats become available. &lt;br /&gt;&lt;br /&gt;Hope to see you there!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-6326633704691823769?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/4gYDe5nfBSg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/6326633704691823769/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=6326633704691823769" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/6326633704691823769?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/6326633704691823769?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/4gYDe5nfBSg/speaking-at-jfokus-2010.html" title="Speaking at Jfokus 2010" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2010/01/speaking-at-jfokus-2010.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4BRXs9eip7ImA9WxBQEEk.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-7606285671389657621</id><published>2010-01-09T14:30:00.003+01:00</published><updated>2010-01-09T14:32:34.562+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-09T14:32:34.562+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DDD" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="spam" /><title>DDD classes winter/spring 2010</title><content type="html">These are the winter and spring dates for our Domain-Driven Design classes, offered in partnership with Domain Language, Inc.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.citerus.se/dddfeb10"&gt;Februrary 18, One-day DDD overview&lt;/a&gt;.&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.citerus.se/dddmar10"&gt;March 9, Four-day Hands-on Immersion&lt;/a&gt;.  &lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;The introduction class is a great way to get a good overview of Domain-Driven Design. Morning is spent on tactical design and how to interact with Domain Experts, and the afternoon is all about strategic design, context mapping and distillation.&lt;br /&gt;&lt;br /&gt;In the four-day immersion class we really learn how to put the domain model to work. It is highly interactive with programming labs, design discussions, modelling sessions, and much more!&lt;br /&gt;&lt;br /&gt;All classes are offered in Swedish in Stockholm. The classes are official DDD classes designed by &lt;a href="http://www.domainlanguage.com/"&gt;Eric Evans, Domain Language Inc&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-7606285671389657621?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/RPbABsD_4Gg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/7606285671389657621/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=7606285671389657621" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/7606285671389657621?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/7606285671389657621?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/RPbABsD_4Gg/ddd-classes-winterspring-2010.html" title="DDD classes winter/spring 2010" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2010/01/ddd-classes-winterspring-2010.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU8NQnw-fip7ImA9WxNbFEU.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-3107949271270235935</id><published>2009-11-17T19:49:00.004+01:00</published><updated>2009-11-17T19:51:33.256+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-17T19:51:33.256+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="development reading" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><title>New Citerus blogger</title><content type="html">Say hi to Mikael Boman's new blog &lt;a href="http://miboman.blogspot.com"&gt;The wheel of destiny&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;First entry is about &lt;a href="http://miboman.blogspot.com/2009/11/top-six-technical-practices-every_17.html"&gt;The top six technical practices every Product Owner must know about&lt;/a&gt;. Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-3107949271270235935?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/FdMJZy7_jbs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/3107949271270235935/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=3107949271270235935" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/3107949271270235935?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/3107949271270235935?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/FdMJZy7_jbs/new-citerus-blogger.html" title="New Citerus blogger" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/11/new-citerus-blogger.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkENSX0_eyp7ImA9WxNUEkU.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-2465597665231408093</id><published>2009-11-03T21:51:00.006+01:00</published><updated>2009-11-03T22:44:58.343+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-03T22:44:58.343+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="development" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><title>From Java to Clojure, followup followup</title><content type="html">&lt;a href="http://martinsventil.blogspot.com/"&gt;Martin Lübcke&lt;/a&gt; came up with this solution to the frequency sorting problem presented in the PNEHM article &lt;a href="http://pnehm.citerus.se/kunskap/pnehm/pnehmartiklar/fromjavatoclojure.5.1fe8f33123572b59ab800023092.html"&gt;From Java to Clojure&lt;/a&gt;:&lt;br /&gt;&lt;pre class="brush: clojure"&gt;&lt;br /&gt;(defn order-by-freq [coll] &lt;br /&gt;  (keys (sort-by #(vector (- (frest %)) (first %)) (frequencies coll))))&lt;br /&gt;&lt;/pre&gt;Replace &lt;i&gt;frest&lt;/i&gt; with &lt;i&gt;fnext&lt;/i&gt; for Clojure 1.0.&lt;br /&gt;&lt;br /&gt;When it comes to performance, this version is about as fast as the original version in the article, but it sure is compact, and surprisingly readable. Many thanks to Martin!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-2465597665231408093?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/X0y5tqSJAmA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/2465597665231408093/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=2465597665231408093" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/2465597665231408093?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/2465597665231408093?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/X0y5tqSJAmA/from-java-to-clojure-followup-followup.html" title="From Java to Clojure, followup followup" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/11/from-java-to-clojure-followup-followup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMARnY4eip7ImA9WxNUEUw.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-5716115399791797550</id><published>2009-11-01T22:19:00.000+01:00</published><updated>2009-11-01T22:20:47.832+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-01T22:20:47.832+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="music" /><title>Music for the Fall</title><content type="html">Autumn 2009 &lt;a href="spotify:user:patrikfr:playlist:2Oa9PllvhY5KcLLLJDNMku"&gt;spotify:user:patrikfr:playlist:2Oa9PllvhY5KcLLLJDNMku&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-5716115399791797550?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/1w-LmkEQNWE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/5716115399791797550/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=5716115399791797550" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/5716115399791797550?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/5716115399791797550?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/1w-LmkEQNWE/music-for-fall.html" title="Music for the Fall" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/11/music-for-fall.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUEHQ38-fSp7ImA9WxNVFko.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-2992415502488027486</id><published>2009-10-27T22:00:00.003+01:00</published><updated>2009-10-27T22:07:12.155+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-27T22:07:12.155+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="development" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><category scheme="http://www.blogger.com/atom/ns#" term="reading" /><title>New Citerus Blogger</title><content type="html">Follow Mattias Holmqvist's new blog "&lt;a href="http://mattiasholmqvist.se/"&gt;Learning more about software development&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;The first two posts focus on, yes, you guessed it, &lt;a href="http://www.clojure.org/"&gt;Clojure&lt;/a&gt;, as Mattias works through some examples from &lt;a href="http://mitpress.mit.edu/sicp/"&gt;Structure and Interpretation of Computer Programs&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-2992415502488027486?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/suY6ObX0-Yw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/2992415502488027486/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=2992415502488027486" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/2992415502488027486?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/2992415502488027486?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/suY6ObX0-Yw/new-citerus-blogger.html" title="New Citerus Blogger" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/10/new-citerus-blogger.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08CRng9fip7ImA9WxNVFko.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-8368958889036218775</id><published>2009-10-27T20:19:00.001+01:00</published><updated>2009-10-27T21:37:47.666+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-27T21:37:47.666+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><title>From Java to Clojure  Followup</title><content type="html">Interest in the &lt;a href="http://pnehm.citerus.se/kunskap/pnehm/pnehmartiklar/fromjavatoclojure.5.1fe8f33123572b59ab800023092.html"&gt;From Java to Clojure&lt;/a&gt; article has been pretty big, rarely before have we seen a PNEHM!-article getting so much attention!&lt;br /&gt;&lt;br /&gt;I have also gotten some great feedback, in particular &lt;a href="http://twitter.com/stuarthalloway/status/5089758364"&gt;Stuart Halloway&lt;/a&gt; suggests that we use Clojure-contrib's &lt;i&gt;seq-utils/frequencies&lt;/i&gt; to improve the code. Since we use &lt;a href="http://commons.apache.org/collections/"&gt;Apache Commons Collections&lt;/a&gt; in the Java version of the code, its only fair for us to dive into the goodness of Clojure-contrib to see what can be of use there.&lt;br /&gt;&lt;br /&gt;Let us start by a quick review of what our final version of the Clojure code looked like:&lt;br /&gt;&lt;pre class="brush: clojure"&gt;&lt;br /&gt;(ns step4.pnehm.clojure-orderer)&lt;br /&gt;&lt;br /&gt;(defn count-words [coll]&lt;br /&gt;   (reduce #(merge-with + %1 {%2 1}) {} coll))&lt;br /&gt;&lt;br /&gt;(defn cmpr [[val1 freq1] [val2 freq2]]&lt;br /&gt;   (let [freq (compare freq2 freq1)]&lt;br /&gt;     (if-not (zero? freq) freq (compare val1 val2))))&lt;br /&gt;&lt;br /&gt;(defn order-by-freq [coll]&lt;br /&gt;   (keys (sort cmpr (count-words coll))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As it turns out, &lt;i&gt;clojure.contrib.seq-utils/frequencies&lt;/i&gt; does exactly what our function &lt;i&gt;count-words&lt;/i&gt; does, as such we can use it as a drop-in replacement. A version which uses contrib now looks like this:&lt;br /&gt;&lt;pre class="brush: clojure"&gt;&lt;br /&gt;(ns withcontrib.pnehm.clojure-orderer&lt;br /&gt;   (:use clojure.contrib.seq-utils))&lt;br /&gt;&lt;br /&gt;(defn cmpr [[val1 freq1] [val2 freq2]]&lt;br /&gt;   (let [freq (compare freq2 freq1)]&lt;br /&gt;   (if-not (zero? freq) freq (compare val1 val2))))&lt;br /&gt;&lt;br /&gt;(defn order-by-freq [coll]&lt;br /&gt;  (keys (sort cmpr (frequencies coll))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We have to make sure we &lt;code&gt;:use clojure.contrib.seq-utils&lt;/code&gt;, and then we can replace our call to &lt;i&gt;count-words&lt;/i&gt;, with a call to &lt;i&gt;frequencies&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Now, for extra credits, let's look inside the frequencies function in Clojure-contrib, to see what i looks like:&lt;br /&gt;&lt;pre class="brush: clojure"&gt;&lt;br /&gt;(defn frequencies&lt;br /&gt;  "Returns a map from distinct items in coll to the number of times&lt;br /&gt;  they appear."&lt;br /&gt;  [coll]&lt;br /&gt;  (reduce (fn [counts x]&lt;br /&gt;              (assoc counts x (inc (get counts x 0))))&lt;br /&gt;          {} coll))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The implementation is quite different from our own, it feels a bit more straight-forward and intuitive. Initially, an empty map is created. As the collection is reduced a copy of the map is created for each processed item and the item is added with an incremented count (if the item already is in the map) or added to the new map with a count of one (if it is the first time the item is processed). &lt;i&gt;get&lt;/i&gt;, gets a value from the map given a key, if there is no match the default, '0', is returned. &lt;i&gt;inc&lt;/i&gt; increments the value, and &lt;i&gt;assoc&lt;/i&gt; associates the value to a key in the map.&lt;br /&gt;&lt;br /&gt;Not only is this version simpler than our own (which is good), it's also much faster (also good). Using &lt;i&gt;seq-utils/frequencies&lt;/i&gt; a sample run with our micro-benchmark now looks like this (sorting 100 characters with 10000 samples):&lt;br /&gt;&lt;br /&gt;Java: 120 ms&lt;br /&gt;Groovy: 538 ms&lt;br /&gt;Time Clojure: 563 ms&lt;br /&gt;&lt;br /&gt;Excellent!&lt;br /&gt;&lt;br /&gt;So, Joshua Bloch's item 47 in &lt;a href="http://java.sun.com/docs/books/effective/"&gt;Effective Java (2 ed)&lt;/a&gt; applies as always: &lt;i&gt;Know and use the libraries&lt;/i&gt;. If you get the feeling that someone must have done what you are about to do before you, someone most probably have.&lt;br /&gt;&lt;br /&gt;Many thanks to Stuart Halloway (who will be at &lt;a href="http://www.oredev.org/"&gt;Øredev&lt;/a&gt; next week, don't miss it!).&lt;br /&gt;&lt;br /&gt;The sources at &lt;a href="http://code.google.com/p/pnehm-java-to-cool-language-x/"&gt;http://code.google.com/p/pnehm-java-to-cool-language-x/&lt;/a&gt; have been updated with the alternative version.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-8368958889036218775?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/C1O8u0I0e2s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/8368958889036218775/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=8368958889036218775" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/8368958889036218775?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/8368958889036218775?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/C1O8u0I0e2s/from-java-to-clojure-followup.html" title="From Java to Clojure  Followup" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/10/from-java-to-clojure-followup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEIAQXc9fyp7ImA9WxNWGUU.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-8002202933903989453</id><published>2009-10-19T21:55:00.002+02:00</published><updated>2009-10-19T22:02:20.967+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-19T22:02:20.967+02:00</app:edited><title>From Java to Clojure</title><content type="html">In &lt;a href="http://pnehm.citerus.se/kunskap/pnehm/pnehmartiklar/fromjavatoclojure.5.1fe8f33123572b59ab800023092.html"&gt;this article&lt;/a&gt;, published in Citerus’ newsletter PNEHM!, I introduce Clojure to Java developers by converting a piece of Java code to Clojure. The article examines how to call Java code from Clojure and Clojure code from Java, complete with &lt;a href="http://code.google.com/p/pnehm-java-to-cool-language-x/"&gt;source code&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Citerus’ consultant &lt;a href="http://peterbacklund.blogspot.com"&gt;Peter Backlund&lt;/a&gt; took the same journey some months ago with his article &lt;a href="http://pnehm.citerus.se/kunskap/pnehm/pnehmartiklar/franjavatillgroovy.5.30c78e2811e644991e780001338.html"&gt;Från Java till Groovy&lt;/a&gt; (in Swedish).&lt;br /&gt;&lt;br /&gt;Read &lt;a href="http://pnehm.citerus.se/kunskap/pnehm/pnehmartiklar/fromjavatoclojure.5.1fe8f33123572b59ab800023092.html"&gt;From Java to Clojure.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-8002202933903989453?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/ulGY-_fyGCo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/8002202933903989453/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=8002202933903989453" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/8002202933903989453?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/8002202933903989453?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/ulGY-_fyGCo/from-java-to-clojure.html" title="From Java to Clojure" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/10/from-java-to-clojure.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQFQno7fyp7ImA9WxNWEE4.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-3920225745685338846</id><published>2009-10-08T22:17:00.006+02:00</published><updated>2009-10-08T23:28:33.407+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-08T23:28:33.407+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="DDD" /><category scheme="http://www.blogger.com/atom/ns#" term="development" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="spam" /><title>DDDSample Presentation (free event)</title><content type="html">On Thursday evening, October 22, &lt;a href="http://groups.google.com/group/swedenspring"&gt;Sweden Spring User Group&lt;/a&gt; is hosting an even in Stockholm where &lt;a href="http://peterbacklund.blogspot.com/"&gt;Peter Backlund&lt;/a&gt; (mostly) and I (less) will present the current state of the &lt;a href="http://dddsample.sf.net/"&gt;DDDSample&lt;/a&gt; application.&lt;br /&gt;&lt;h4&gt;Agenda&lt;/h4&gt;&lt;i&gt;DDDSample är en Spring-applikation som utvecklats för att påvisa hur idéer och koncept från Domain-Driven Design kan implementeras i en modern utvecklingsstack. Applikationen utvecklas i samarbete med Eric Evans, författare till boken Domain-Driven Design, och syftar till att visa hur mönster från DDD konkret kan användas för att skapa en systemarkitektur för att lösa problem i en komplex domän, utan att skapa onödig teknisk komplexitet.&lt;br /&gt; &lt;br /&gt;Sedan applikationen först introducerades för drygt ett år sedan har den kontinuerligt utvecklats, mycket tack vara den feedback som kommit från olika communities. Det är snart dags för en ny release och under denna träff kommer vi kika närmare på applikationens olika delar och se hur dessa mappar mot koncept inom Domain-Driven Design.&lt;br /&gt;&lt;br /&gt;Vi kommer att visa hur Spring (och i viss mån andra ramverk) hjälper oss att programmera domändrivet genom att dels låta oss bygga en ren och rik modell i Java, och dels genom att ta hand om infrastrukturell kod och låta oss fokusera på affärsnytta (focus on the core domain).&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The presentation will be in Swedish and the event is free to attend.&lt;br /&gt;&lt;br /&gt;Sign up at &lt;a href="http://www.eventbrite.com/event/445416252"&gt;http://www.eventbrite.com/event/445416252&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Welcome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-3920225745685338846?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/dH_omH4QZg4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/3920225745685338846/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=3920225745685338846" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/3920225745685338846?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/3920225745685338846?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/dH_omH4QZg4/dddsample-presentation-free-event.html" title="DDDSample Presentation (free event)" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/10/dddsample-presentation-free-event.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UERX86fCp7ImA9WxNXGUk.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-2301326244158068930</id><published>2009-10-06T17:42:00.014+02:00</published><updated>2009-10-07T21:53:24.114+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-07T21:53:24.114+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="development" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title>Mocking to the Rescue!</title><content type="html">I am not really a big fan of mocking. My experience is that if you design your code to be testable, you only rarely have to rely on mocks, instead you'll be fine just by stubbing an interface or two. But even as a proponent of what &lt;a href="http://martinfowler.com/articles/mocksArentStubs.html"&gt;Martin Fowler calls classic TDD&lt;/a&gt;, I find it there are times when a mocking tool can come in handy. One situation is when you have to work with API:s that lack good interfaces, in these cases a good mocking tool with support for mocking concrete classes can be of great help.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.mockito.org/"&gt;Mockito&lt;/a&gt; is what I would like to consider a next-generation mocking tool, with support for both mocking and stubbing. Mockito fully and naturally uses recent language enhancements in Java, such as generics, static imports and annotations, to make the tool easy to use. Writing clean and elegant test code that is easy to understand can actually be pretty simple. TheMockito API is straightforward and well designed, the need for infrastructure code is kept to a minimum. If you are an EasyMock user, this comparison may be helpful when following along in the code below: &lt;a href="http://code.google.com/p/mockito/wiki/MockitoVSEasyMock"&gt;http://code.google.com/p/mockito/wiki/MockitoVSEasyMock&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Let's look at a few examples!&lt;h3&gt;Stub an interface&lt;/h3&gt;A nice property of systems built using dependency injection is that you get loosely coupled systems with well-defined interfaces that are easy to stub for testing. It is easy enough to provide stub implementations of these interface directly in the test classes, e.g. as anonymous implementations or inner classes. But despite this, I have found myself more and more starting to rely on Mockito for these situations, it's fewer lines of code, and very convenient!&lt;br /&gt;&lt;pre class="brush: java"&gt;import static org.mockito.Mockito.mock;&lt;br /&gt;import static org.mockito.Mockito.when;&lt;br /&gt;import static org.mockito.Mockito.verify;&lt;br /&gt;import static org.junit.Assert.assertEquals;&lt;br /&gt;&lt;br /&gt;[...]&lt;br /&gt;&lt;br /&gt;ClientRepository repository = mock(ClientRepository.class);&lt;br /&gt;ClientId clientId = new ClientId(123);&lt;br /&gt;Client client = new Client(clientId, new Name("Test", "User"));&lt;br /&gt;when(repository.findById(clientId)).thenReturn(client);&lt;/pre&gt;Now, as an example, we can use our ClientRepository instance to test a service class:&lt;br /&gt;&lt;pre class="brush: java"&gt;FancyService service = new FancyServiceImpl();&lt;br /&gt;service.setRepository(repository);&lt;br /&gt;assertEquals(client, service.findClientAndDoSomethingTrulyAwesome(123));&lt;/pre&gt;When stubbing like this we are usually not that interested in verifying behaviour of the stub. But if we, for some reason, would like to explicitly make sure that the method &lt;code&gt;findById(...)&lt;/code&gt; was called, we can do this with the following line of code:&lt;br /&gt;&lt;pre class="brush: java"&gt;verify(repository).findById(clientId);&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Stubbing concrete classes&lt;/h3&gt;Now and then you encounter API:s that were not as designed for testing that you could wish for. In these cases, the possibilities of stubbing concrete classes can be very helpful.&lt;h4&gt;Restlet&lt;/h4&gt;&lt;a href="http://www.restlet.org/"&gt;Restlet&lt;/a&gt; is a Java framework for creating RESTful web service. Reslet consists of quite a big API, and the authors have, among other things, decide to create their own implementation of things like &lt;code&gt;Request&lt;/code&gt;, &lt;code&gt;Response&lt;/code&gt;, &lt;code&gt;Status.SUCCESS_OK&lt;/code&gt; (HTTP response 200) etc. Unfortunately, many parts of the API consists of concrete classes, instead of interfaces. One downside of this is that it is sometimes hard to write tests for code that uses the Restlet APIs.&lt;br /&gt;&lt;br /&gt;Stubbing the concrete class &lt;code&gt;org.restlet.data.Response&lt;/code&gt; is easily done in the same way we stubbed the &lt;code&gt;ClientRepository&lt;/code&gt; interface above:&lt;br /&gt;&lt;pre class="brush: java"&gt;import static org.mockito.Mockito.*;&lt;br /&gt;import org.restlet.data.Response;&lt;br /&gt;import org.restlet.data.Status;&lt;br /&gt;import org.restlet.resource.Representation;&lt;br /&gt;&lt;br /&gt;[...]&lt;br /&gt;&lt;br /&gt;Response response = mock(Response.class);&lt;br /&gt;Representation entity = mock(Representation.class);&lt;br /&gt;when(response.getStatus()).thenReturn(Status.SUCCESS_OK);&lt;br /&gt;when(response.getEntity()).thenReturn(entity);&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;Quartz&lt;/h4&gt;&lt;a href="http://www.opensymphony.com/quartz/"&gt;Quartz&lt;/a&gt; is a scheduling component that is supported and also used by many popular application development frameworks and application servers, including Spring and Seam. When using Quartz you define jobs that execute according to a schedule. Every time a job is triggered a new instance of the job class is created, and executed. If state is to be saved between job executions it has to be stored in some kind data structure outside of the job. Quartz makes a context available, &lt;code&gt;org.quartz.JobExecutionContext&lt;/code&gt;, for this and other purposes. The context is handed to every newly created job instance. The context can, a bit simplified, be viewed as &lt;code&gt;Map&lt;/code&gt; where the job can store and retrieve data.&lt;br /&gt;&lt;br /&gt;If we would like to make data available to a job or read the result from a job execution we have to create an instance of &lt;code&gt;JobExecutionContext&lt;/code&gt; and hand to our job. Creating this instance is however quite complicated, and since Quartz also tends to favor concrete classes over interfaces, it makes it hard for us to provide our own implementation. Fortunately, Mockito (or another mocking tool that can mock concrete classes) can help us out here as well!&lt;br /&gt;&lt;br /&gt;Use Mockito to setup the context and set a fictional &lt;code&gt;indexCount&lt;/code&gt; parameter as input value to the job:&lt;br /&gt;&lt;pre class="brush: java"&gt;import static org.mockito.Mockito.*;&lt;br /&gt;import org.quartz.JobDataMap;&lt;br /&gt;import org.quartz.JobDetail;&lt;br /&gt;import org.quartz.JobExecutionContext;&lt;br /&gt;&lt;br /&gt;[...]&lt;br /&gt;&lt;br /&gt;JobExecutionContext ctx = mock(JobExecutionContext.class);&lt;br /&gt;JobDetail detail = mock(JobDetail.class);&lt;br /&gt;JobDataMap map = new JobDataMap();&lt;br /&gt;map.put("indexCount", 145);&lt;br /&gt;when(detail.getJobDataMap()).thenReturn(map);&lt;br /&gt;when(ctx.getJobDetail()).thenReturn(detail);&lt;/pre&gt;Now we can use the context in our test:&lt;br /&gt;&lt;pre class="brush: java"&gt;IndexUpdaterJob job = new IndexUpdater();&lt;br /&gt;job.execute(ctx);&lt;/pre&gt;And verify that the index was updated:&lt;br /&gt;&lt;pre class="brush: java"&gt;map = ctx.getJobDetail().getJobDataMap();&lt;br /&gt;assertEquals(146, map.get("indexCount"));&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Mocking&lt;/h3&gt;As the name suggests, Mockito can of course be used for different kinds of mocking as well. For more examples, have a look at the &lt;a href="http://mockito.googlecode.com/svn/branches/1.8.0/javadoc/org/mockito/Mockito.html"&gt;Mockito documentation&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-2301326244158068930?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/oyI7MiRqQf4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/2301326244158068930/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=2301326244158068930" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/2301326244158068930?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/2301326244158068930?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/oyI7MiRqQf4/mocking-to-rescue.html" title="Mocking to the Rescue!" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/10/mocking-to-rescue.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkIMRX8_eCp7ImA9WxNXE08.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-5329617921649442577</id><published>2009-09-30T18:34:00.001+02:00</published><updated>2009-09-30T18:36:24.140+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-30T18:36:24.140+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="spam" /><title>Follow Citerus on Twitter</title><content type="html">What the title says: &lt;a href="http://twitter.com/citerus_se"&gt;@citerus_se&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-5329617921649442577?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/tIm86Hb11Rk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/5329617921649442577/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=5329617921649442577" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/5329617921649442577?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/5329617921649442577?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/tIm86Hb11Rk/follow-citerus-on-twitter.html" title="Follow Citerus on Twitter" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/09/follow-citerus-on-twitter.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MDQXc6fSp7ImA9WxNXGUk.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-1964064047131777214</id><published>2009-09-21T19:27:00.008+02:00</published><updated>2009-10-07T21:57:50.915+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-07T21:57:50.915+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><title>Geeky Fact of the Day</title><content type="html">I read &lt;a href="http://twitter.com/joshbloch/statuses/4080292481 "&gt;this tweet&lt;/a&gt; by &lt;a href="http://twitter.com/joshbloch"&gt;Joshua Bloch&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;"Geeky fact of the day: the sum of the first n cubes equals the square&lt;br /&gt;of the sum of the first n integers"&lt;br /&gt;&lt;br /&gt;And decide to throw some Clojure at it:&lt;br /&gt;&lt;pre class="brush: clojure"&gt;(use 'clojure.contrib.math)&lt;br /&gt;&lt;br /&gt;(defn geeky-fact [n]&lt;br /&gt;  (=&lt;br /&gt;    (reduce + (map #(expt % 3) (take n (iterate inc 1))))&lt;br /&gt;    (expt (reduce + (take n (iterate inc 1))) 2)))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-1964064047131777214?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/OJWBYNkNSKo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/1964064047131777214/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=1964064047131777214" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/1964064047131777214?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/1964064047131777214?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/OJWBYNkNSKo/geeky-fact-of-day.html" title="Geeky Fact of the Day" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/09/geeky-fact-of-day.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8HRXYzfyp7ImA9WxNVEkk.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-8805144984381117787</id><published>2009-09-01T20:15:00.012+02:00</published><updated>2009-10-22T22:20:34.887+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-22T22:20:34.887+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="development" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><title>Clojure Crash Course For Java Developers</title><content type="html">&lt;i&gt;Updated, fixed bug in test-vec def&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Looking at Clojure code coming from a Java background may be quite a daunting experience at first. So I have put together a short introduction that I hope can facilitate going from Java to Clojure.&lt;br /&gt;&lt;br /&gt;Clojure is a functional programming language. As such we use functions to manipulate data, we avoid mutable state and side-effects. In a way it can be viewed as programming Java with only static methods and immutable objects. At first this may sound like a huge limitation, but in contrast to Java, functions in Clojure are are first-class citizens and Clojure fully support higher-order functions. That is, we can treat functions like any other piece of data, functions can be assigned to variables, functions can be passed as arguments to other functions and we can write functions that return functions. This can be very powerful and by keeping data immutable and strive for side-effect free behavior the idea is that we can write more robust programs that&amp;nbsp; more easily can scale to multiple cores.&lt;br /&gt;&lt;br /&gt;Clojure is a homoiconic language, that is, data and program instructions are represented the same way. This may look weird at first, and could need some time getting used to. Clojure programs typically starts out as text (in a text file) and is converted by a &lt;i&gt;reader&lt;/i&gt; into data structures used by the compiler. The reader reads the text &lt;i&gt;form&lt;/i&gt; by &lt;i&gt;form&lt;/i&gt;. A form is a chunk of data that can be translated into a Clojure data structure. Numbers, like &lt;i&gt;123&lt;/i&gt;, are forms, so are lists, &lt;i&gt;(+ 1 2)&lt;/i&gt; and vectors, &lt;i&gt;[1 2 3]&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Program and data are expressed as s-expressions, symbolic expressions, in a parenthesized prefix-notation. I.e. the function comes first and the data follows. The Clojure expression for adding the numbers 1, 2, and 3 is: &lt;span style="FONT-FAMILY:Courier New"&gt;(+ 1 2 3)&lt;/span&gt; This is a list and as such it will be evaluated as a function call. The function is &lt;span style="FONT-FAMILY:Courier New"&gt;+&lt;/span&gt; and the data to apply the function on comes after that.&lt;br /&gt;&lt;br /&gt;Expressions can be, and typically are nested: &lt;span style="FONT-FAMILY:Courier New"&gt;(+ 1 2 3 (- 2 3))&lt;/span&gt; =&amp;gt; &lt;span style="FONT-FAMILY:Courier New"&gt;5&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;REPL&lt;/b&gt;&lt;br /&gt;The Read Evaluate Print Loop is an excellent tool to use when experimenting with Clojure. It is part of the Clojure distribution, so download and set it up before we proceed, and you will be able to try out things live as we look closer at the language:&lt;br /&gt;&lt;br /&gt;1) &lt;a href=http://code.google.com/p/clojure/downloads/list id=ag:r title="Download Clojure"&gt;Download Clojure&lt;/a&gt; (examples below are for Clojure 1.0.0).&lt;br /&gt;2) Extract the zip and run &lt;span style="FONT-FAMILY:Courier New"&gt;java -cp clojure-1.0.0.jar clojure.lang.Repl&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;You should see something like:&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&lt;br /&gt;Clojure 1.0.0-&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Where &lt;span style="FONT-FAMILY:Courier New"&gt;user&lt;/span&gt; indicates the current namespace.&lt;br /&gt;&lt;br /&gt;For a somewhat more comfortable REPL experience, add the &lt;a href=http://jline.sourceforge.net/ id=rnc. title=JLine&gt;JLine&lt;/a&gt; ConsoleRunner:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;java -cp jline-0.9.94.jar:clojure-1.0.0.jar jline.ConsoleRunner clojure.lang.Repl&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Forms&lt;/b&gt;&lt;br /&gt;We have already met the numeric form, which is a literal, the vector, and the list but there are other forms as well:&lt;br /&gt;&lt;br /&gt;Symbols:&lt;br /&gt;Symbols are used to name things such as functions, namespaces (a Clojure equivalent of Java packages) and Java classes. We have already seen one: the &lt;span style="FONT-FAMILY:Courier New"&gt;+&lt;/span&gt; operator, which is a function.&lt;br /&gt;&lt;br /&gt;Literals:&lt;br /&gt;Strings, numbers, characters, &lt;span style="FONT-FAMILY:Courier New"&gt;nil&lt;/span&gt; (Java &lt;span style="FONT-FAMILY:Courier New"&gt;null&lt;/span&gt;), booleans (&lt;span style="FONT-FAMILY:Courier New"&gt;true&lt;/span&gt;, &lt;span style="FONT-FAMILY:Courier New"&gt;false&lt;/span&gt;) and keywords. Keywords are like symbols but begins with a colon e.g. &lt;span style="FONT-FAMILY:Courier New"&gt;:color&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Map:&lt;br /&gt;Much like Java Maps, Clojure maps are zero or more key/value pairs enclosed in braces: &lt;span style="FONT-FAMILY:Courier New"&gt;{:language "Clojure", :kind "Functional"} &lt;/span&gt;&lt;br /&gt;(commas are treated like witespace, leave them out if you like)&lt;br /&gt;&lt;br /&gt;Set:&lt;br /&gt;Much like Java Set, Clojure sets are zero or more forms enclosed in braces with a leading #: &lt;span style="FONT-FAMILY:Courier New"&gt;#{:red :green :orange}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;These forms are translated in to data structures by the reader and compiler. More on Clojure data structures, their characteristics, related functions and relation to Java can be found on the &lt;a href=http://clojure.org/data_structures&gt;Clojure Data Structures page&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Special Forms&lt;/b&gt;&lt;br /&gt;In addition to the forms we have mentioned so far we have what are called "special forms", these are forms evaluated in a special way to do things normal forms can not do. There are a few particularily important ones:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;(def symbol init?)&lt;/i&gt;&lt;br /&gt;Binds a symbol to a global var in the current namespace, this is used to define things we need access to, e.g. a function or a value. Try it out using the REPL:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (def a 42)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; #'user/a&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; a&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; 42&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;(if test then else?)&lt;/i&gt;&lt;br /&gt;Evaluate &lt;i&gt;test&lt;/i&gt;, if not nil or false, evaluate &lt;i&gt;then&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&lt;span style=FONT-FAMILY:Verdana&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;(if (&amp;gt; 3 2) "TRUE" "FALSE")&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; "TRUE"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;(let [bindings* ] exprs*)&lt;/i&gt;&lt;br /&gt;Create local bindings used when evaluating &lt;i&gt;exprs*&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&lt;span style=FONT-FAMILY:Verdana&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;(let [a 2] (&amp;gt; a 3))&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;(fn name? [params* ] exprs*)&lt;/i&gt;&lt;br /&gt;Defines a function. If we don't need to refer to the function, we can make it anonymous by not supplying a name:&lt;br /&gt;&lt;br /&gt;Create a function that adds two values, and immediately call it on 1 and 2:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&lt;span style=FONT-FAMILY:Verdana&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;((fn [a b] (+ a b)) 1 2)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; 3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;More special forms: &lt;a href=http://clojure.org/special_forms id=h_4x title=http://clojure.org/special_forms&gt;http://clojure.org/special_forms&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Macros&lt;/b&gt;&lt;br /&gt;Clojure macros make it possible to add new functionality to the language, for instance by combining primitive forms. As a Clojure beginner you can safely ignore Clojure's macro functionality until you feel more confident in the language. But it can be good to know that many constructs in Clojure are macros, but they look just like ordinary functions. One of the most commonly used ones are probably &lt;i&gt;(defn name doc-string? attr-map? [params*] body)&lt;/i&gt;, used to create and name functions globally:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&lt;span style=FONT-FAMILY:Verdana&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;(defn add [a b] (+ a b))&lt;br /&gt;&amp;gt; #'user/add&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&lt;span style=FONT-FAMILY:Verdana&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (add 2 3)&lt;br /&gt;&amp;gt; 5&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Using the function &lt;i&gt;macroexpand&lt;/i&gt; we can see that &lt;i&gt;defn&lt;/i&gt; is infact a combination of &lt;i&gt;def&lt;/i&gt; and &lt;i&gt;fn&lt;/i&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (macroexpand '(defn add [a b] (+ a b)))&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; (def add (clojure.core/fn ([a b] (+ a b))))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Immutable data.&lt;/b&gt;&lt;br /&gt;The set of data structures in Clojure is extensive. We met a few of the structures when we talked about forms above. An important of property of Clojure data structures is that they are immutable. For example, operations on a list returns a new list with the result of the operation. The original list is untouched. We'll see examples of this below.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Functions&lt;/b&gt;&lt;br /&gt;There is quite an extensive set of functions in the core Clojure libraries. Mathematical functions are named after their common symbols, as you would expect:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (+ 1 2)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; 3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (* 2 5)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; 10&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (&amp;gt; 1 4)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are also many functions to work on collections:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (def test-vec [1 2 3 4 5 6 7 8 9 10])&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;#'user/test-vec&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;conj&lt;/i&gt; adds an element to the collection:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (conj test-vec 11)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; [1 2 3 4 5 6 7 8 9 10 11]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;map&lt;/i&gt; applies a given function to all elements of a collection, returning a new collection with the result:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;(user=&amp;gt; (map #(* % 10) test-vec)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; (10 20 30 40 50 60 70 80 90 100)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The construct &lt;span style="FONT-FAMILY:Courier New"&gt;#(* % 10)&lt;/span&gt; is a reader macro for anonymous functions, the &lt;span style="FONT-FAMILY:Courier New"&gt;%&lt;/span&gt; is short for &lt;span style="FONT-FAMILY:Courier New"&gt;%1&lt;/span&gt; and is bound to the first (and here, only) argument. We could also have written this using the fn form:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (map (fn [a] (* a 10)) test-vec)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; (10 20 30 40 50 60 70 80 90 100)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;filter&lt;/i&gt; will keep all elements for which the given function evaluates to true:&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (filter even? test-vec)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;(2 4 6 8 10)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Again, all these functions return a new collection, our initial &lt;span style="FONT-FAMILY:Courier New"&gt;test-vec&lt;/span&gt; is untouched.&lt;br /&gt;&lt;br /&gt;See the complete &lt;a href=http://clojure.org/api id=hvc1 title="Clojure APIs"&gt;Clojure APIs&lt;/a&gt; for all core functions. In addition to Clojure core there is also the core &lt;a href=http://richhickey.github.com/clojure-contrib/ id=pu.i title=clojure-contrib&gt;clojure-contrib&lt;/a&gt;, a user maintained library that also acts as an incubator for Clojure core.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Java integration&lt;/b&gt;&lt;br /&gt;Clojure runs on the JVM and is designed to make it easy to call Java code from Clojure, and Clojure code from Java. This is a big benefit as we can always drop down to Java if there is something we need that is missing from the Clojure libraries.&lt;br /&gt;&lt;br /&gt;Calling Java is done using the . (dot) special form:&lt;br /&gt;&lt;br /&gt;Accessing a static field:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (. Math PI)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; 3.141592653589793&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Calling a static method:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (. Math min 3 4)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; 3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Creating a new instance is done using &lt;i&gt;new:&lt;br /&gt;&lt;br /&gt;&lt;/i&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (def l (new java.util.ArrayList))&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; #'user/l&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Accessing an instance method, again using the . form:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (. l size)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; 0&lt;/span&gt;&lt;br style="FONT-FAMILY:Courier New"&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (. l add "Cheese")&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; true&lt;/span&gt;&lt;br style="FONT-FAMILY:Courier New"&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (. l get 0)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; "Cheese"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Note here that as we access the &lt;span style="FONT-FAMILY:Courier New"&gt;ArrayList&lt;/span&gt; instance it behaves as expected in Java. Clojure's immutability is not extended to Java objects, they keep their original behavior.&lt;br /&gt;&lt;br /&gt;This is the basics of Java interoperability, but there is a lot of syntactic sugar available to make Java easier to work with from Clojure:&lt;br /&gt;&lt;br /&gt;Direct static member access can be written with &lt;span style="FONT-FAMILY:Courier New"&gt;/&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; Math/PI&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; 3.141592653589793&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If it's a static method, make it a call:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (Math/min 3 4)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; 3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Object creation can be done with &lt;i&gt;Classname&lt;/i&gt;.:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (def l (java.util.ArrayList.))&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; #'user/l&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If it feels annoying having to fully qualify &lt;span style="FONT-FAMILY:Courier New"&gt;ArrayList&lt;/span&gt;, we can import it (&lt;span style="FONT-FAMILY:Courier New"&gt;Math&lt;/span&gt;, as used above, is in &lt;span style="FONT-FAMILY:Courier New"&gt;java.lang&lt;/span&gt; and is imported by default):&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (import '(java.util ArrayList))&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; java.util.ArrayList&lt;/span&gt;&lt;br style="FONT-FAMILY:Courier New"&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (def l (ArrayList.))&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; #'user/l&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The ' (quote) used above is another reader macro preventing the list to be evaluated as a function call.&lt;br /&gt;&lt;br /&gt;Instance calls can be shoretened by placing the thing we want to call, the method, first, prefix Clojure style:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (.add l "Cheese")&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Chaining Java calls in Clojure looks a bit messy by default:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (. (. (. l get 0)&amp;nbsp; (subSequence 1 3)) length)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Using the .. notation we can do this:&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;user=&amp;gt; (.. l (get 0) (subSequence 1 3) length)&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-FAMILY:Courier New"&gt;&amp;gt; 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The &lt;span style="FONT-FAMILY:Courier New"&gt;..&lt;/span&gt; is, again, a Clojure macro, that expands to our first version above.&lt;br /&gt;&lt;br /&gt;&lt;a href=http://clojure.org/java_interop id=u:ok title="More on Java interoperability"&gt;More on Java interoperability&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tooling&lt;/b&gt;&lt;br /&gt;REPL is all good for trying out things at the promt, but for writing larger Clojure programs you'd typicall want to use something else. Comming from a Java background all three major IDE:s have some kind of Clojure support at this point:&lt;br /&gt;&lt;br /&gt;IntelliJ/IDEA: &lt;a href=http://plugins.intellij.net/plugin/?id=4050 id=mdms title="La Clojure plug-in"&gt;La Clojure plug-in&lt;/a&gt;&lt;br /&gt;NetBeans: &lt;a href=http://enclojure.net/ id=dafa title="enclojure plug-in"&gt;enclojure plug-in&lt;/a&gt;&lt;br /&gt;Eclipse: &lt;a href=http://code.google.com/p/clojure-dev/ id=fx6q title=clojure-dev&gt;clojure-dev&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Hopefully this will get you started exploring Clojure. Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-8805144984381117787?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/fSbdXtQ0uUw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/8805144984381117787/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=8805144984381117787" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/8805144984381117787?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/8805144984381117787?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/fSbdXtQ0uUw/clojure-crash-course-for-java.html" title="Clojure Crash Course For Java Developers" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/09/clojure-crash-course-for-java.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAGQHc8fSp7ImA9WxNQEEk.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-4605958288373713175</id><published>2009-08-28T07:50:00.002+02:00</published><updated>2009-09-15T22:32:01.975+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-15T22:32:01.975+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DDD" /><category scheme="http://www.blogger.com/atom/ns#" term="development" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><title>One Man's Entity Is Another Man's Value Object</title><content type="html">One activity that we tend to spend some time on when doing Domain-Driven Design is the characterization of our classes into &lt;a href="http://www.domaindrivendesign.org/node/109"&gt;Entities&lt;/a&gt; of &lt;a href="http://www.domaindrivendesign.org/node/135"&gt;Value Objects&lt;/a&gt;. Entities and Value Objects are two fundamental building blocks that we use to handle complexity and help us further deepen our understanding of the problem domain. Careful characterization can make our design simpler, yet more powerful.&lt;br /&gt;&lt;br /&gt;Here are two things that I like to stress during this work:&lt;br /&gt;1) It's not always obvious what type of building block a model item is.&lt;br /&gt;&lt;br /&gt;Let the characterization process take time, do not be afraid to experiment. Try out a few different key scenarios, both by "modeling out loud" by expressing scenarios in the words of the Ubiquitous Language as conversations with other people on the team, and in code. Work hard to challenge your initial assumptions, refactor as needed. That said, if you have a choice, bias your design towards Value Objects. We favor Value Objects for their uninteresting life-cycle and immutability, we use them to push down complexity. Imagine if &lt;code&gt;java.util.GregorianCalendar&lt;/code&gt; was immutable...&lt;br /&gt;&lt;br /&gt;2) The characterization is &lt;a href="http://www.domaindrivendesign.org/node/91"&gt;context&lt;/a&gt;-dependent, i.e. one man's Entity is another man's Value Object.&lt;br /&gt;&lt;br /&gt;Let's consider money, a popular choice when discussing Value Objects. Imagine I have a SEK 100 note and walk over to a person and ask her if she'd be willing to exchange my note for one of her SEK 100 notes. The person would most likely accept this proposal (after some initial suspiciousness, one can imagine). I get her note and she get's mine. From both our points of view, nothing really happened. I can still go down to the store and buy something priced at SEK 100. She can do the same. The value property of the note is what is important to us, not the particular note instance; as long as they have the same value, they are interchangeable. They are also immutable. When I get a note in my possession, it's value is already set. There is no way I can (legally) change the value written on the note. I pass it along as means of payment and I forget about it. As far as I am concerned it can be garbage collected when I no longer hold on to it.&lt;br /&gt;&lt;br /&gt;However, if I walk over to a person and ask her if we can exchange VISA cards, odds are she won't agree. And we all know why. Our cards may be issued by the same bank, have the same shape and color, and both be VISA cards. But they also have a card number, they have an identity. The actual card instance does matter. Credit cards have a complex life-cycle tracked by this identity; they are issued, lost and cancelled, or stolen, or just expired. They are connected to an account, which may have a huge credit just waiting to be spent, or it may be overdrawn. We think twice before handing over the card to someone, because that someone can do things to our card that we don't want. Evil things. Things like &lt;code&gt;(VisaCard) card.clone()&lt;/code&gt;, or &lt;code&gt;card.charge(2 * amountAgreedUpon)&lt;/code&gt;. In short, credit and debit cards are Entities and we need to handle them with care. Entities are high-maintenance. But can be oh so useful.&lt;br /&gt;&lt;br /&gt;Now, if we scrutinize that SEK 100 note carefully, we will find a number, a serial numbers. So what is this? Notes do have an identity after all? Perhaps they are not Value Objects at all?! What is going on here? Well, I do not know this domain very well, but it is not that hard to imagine that there is someone somewhere that &lt;span style="font-style:italic;"&gt;do&lt;/span&gt; care about tracking individual notes. Perhaps &lt;a href="http://www.riksbank.com/"&gt;Sveriges Riksbank&lt;/a&gt;, Sweden's central bank, uses this information to track individual notes, as they enter them into circulation or destroy them when no longer in use. I bet there is a computer software system somewhere, in a different &lt;a href="http://www.domaindrivendesign.org/node/91"&gt;Bounded Context&lt;/a&gt;, where banknotes are Entities.&lt;br /&gt;&lt;br /&gt;Read more about the Building Blocks of a Model-Driven Design in the &lt;a href="http://www.domaindrivendesign.org/sites/default/files/discussion/PatternSummariesUnderCreativeCommons.doc"&gt;DDD Pattern Summaries (.doc file)&lt;/a&gt;.&lt;br /&gt;Watch Dan Bergh Johnssons presentation &lt;a href="http://archive.oredev.org/topmenu/video/ddd/danberghjohnsson.4.5a2d30d411ee6ffd28880002218.html"&gt;The Power of Value from Øredev 2008&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Heldagsseminarium: &lt;a href="http://www.citerus.se/dddsep09"&gt;Domain-Driven Design, 23 september 2009 i Stockholm&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-4605958288373713175?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/G63VnupP2Z8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/4605958288373713175/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=4605958288373713175" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/4605958288373713175?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/4605958288373713175?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/G63VnupP2Z8/one-manss-entity-is-another-mans-value.html" title="One Man's Entity Is Another Man's Value Object" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/08/one-manss-entity-is-another-mans-value.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAHQ3wzfCp7ImA9WxNQEEk.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-3629203539686582273</id><published>2009-08-19T22:43:00.004+02:00</published><updated>2009-09-15T22:32:12.284+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-15T22:32:12.284+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="development" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><title>Jfokus 2010 Call for Paper Now Open</title><content type="html">The &lt;a href="http://www.jfokus.se"&gt;Jfokus&lt;/a&gt; conference is Sweden's premier conference on Java development, organized by the Swedish Java user group &lt;a href="http://www.javaforum.se"&gt;Javaforum&lt;/a&gt;. As a speaker at both Jfokus 2008 and 2009 I can tell you that Mattias and his team do an excellent work running the conference and it is a really great experience to both attend and speak at the event.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.jfokus.se/jfokus/proposals.jsp?lang=en"&gt;Submit you proposal now&lt;/a&gt; and hopefully we will see each other at Jfokus 2010, January 26 and 27 in Stockholm!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-3629203539686582273?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/GCcFj1U0onI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/3629203539686582273/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=3629203539686582273" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/3629203539686582273?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/3629203539686582273?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/GCcFj1U0onI/jfokus-2010-call-for-paper-now-open.html" title="Jfokus 2010 Call for Paper Now Open" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/08/jfokus-2010-call-for-paper-now-open.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkQBQHY8eip7ImA9WxJaGU0.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-4117368202895210323</id><published>2009-08-10T14:45:00.002+02:00</published><updated>2009-08-10T14:45:51.872+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-10T14:45:51.872+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="spam" /><category scheme="http://www.blogger.com/atom/ns#" term="psa" /><title>Follow The Weak Reference on Twitter</title><content type="html">Follow The Weak Reference on Twitter: &lt;a href="http://www.twitter.com/weakreference"&gt;http://www.twitter.com/weakreference&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-4117368202895210323?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/-vJZxirBRyo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/4117368202895210323/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=4117368202895210323" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/4117368202895210323?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/4117368202895210323?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/-vJZxirBRyo/follow-weak-reference-on-twitter.html" title="Follow The Weak Reference on Twitter" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/08/follow-weak-reference-on-twitter.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMASX4zfSp7ImA9WxNXGUk.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-1035383527594062259</id><published>2009-08-10T14:14:00.007+02:00</published><updated>2009-10-07T22:30:48.085+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-07T22:30:48.085+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="development" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><title>Laziness IS a Virtue of a Programmer</title><content type="html">As it turns out, &lt;a href="http://weakreference.blogspot.com/2007/05/laziness-is-not-virtue-of-programmer.html"&gt;laziness is a virtue of a programmer&lt;/a&gt;...&lt;br /&gt;&lt;br /&gt;It is with particular joy I am rediscovering the programming paradigm that once introduced me to the art of software development: Functional programming. I begun my university studies almost 15 years ago. I initially planned to study biotechnology, but for different reasons I ended up with a M Sc degree in Information Technology Engineering instead. I had not really been doing any serious computer programming prior to my university studies, and the first course they threw at us was this monstrous thing called "Program Construction". It sure was a lot of work, but it built a great foundation for our further studies. And it was all tought in ML. 10+ years of Java followed. March this year I attended &lt;a href="http://qconlondon.com/london-2009/conference/"&gt;QCon London&lt;/a&gt; to give a tutorial on the &lt;a href="http://dddsample.sf.net"&gt;DDDSample app&lt;/a&gt;, and also had the opportunity to listen to Rich Hickey give a presentation on &lt;a href="http://www.clojure.org/"&gt;Clojure&lt;/a&gt;. Since then I have slowly been rediscovering  the beauty of functional programming; map, reduce/fold, higher-order functions, recursion, and more.&lt;br /&gt;&lt;br /&gt;As an example, let's look at Clojure's lazy sequences:&lt;br /&gt;&lt;br /&gt;This gives us a lazy sequence of all whole numbers:&lt;br /&gt;&lt;pre class="brush: clojure"&gt;(def numbers (iterate inc 1))&lt;/pre&gt;&lt;br /&gt;If executed it will define a lazy sequence, i.e. its elements will not be evaluated until needed. This is a good thing in this case since this sequence is infinite.&lt;br /&gt;&lt;br /&gt;We can now use this infinite sequence, for example by calling:&lt;br /&gt;&lt;pre class="brush: clojure"&gt;(take 10 (drop 1000 numbers))&lt;/pre&gt;&lt;br /&gt;which will return the following (lazy) sequence:&lt;br /&gt;&lt;pre class="brush: clojure; first-line: 2"&gt;(1001 1002 1003 1004 1005 1006 1007 1008 1009 1010)&lt;/pre&gt;&lt;br /&gt;Or why not take all the even numbers by filtering the sequence:&lt;br /&gt;&lt;pre class="brush: clojure"&gt;(take 10 (filter even? numbers))&lt;/pre&gt;&lt;br /&gt;returns:&lt;br /&gt;&lt;pre class="brush: clojure; first-line: 2"&gt;(2 4 6 8 10 12 14 16 18 20)&lt;/pre&gt;&lt;br /&gt;I think this is pretty sweet!&lt;br /&gt;&lt;br /&gt;For an upcoming &lt;a href="http://pnehm.citerus.se/"&gt;PNEHM!&lt;/a&gt; article I needed to generate data sets of arbitrary sizes consisting of random letters a-z, so I did this:&lt;br /&gt;&lt;pre class="brush: clojure"&gt;(def s "abcdefghijklmnopqrstuvwxyz")&lt;br /&gt;&lt;br /&gt;(def data-set&lt;br /&gt;  (repeatedly&lt;br /&gt;    #(nth s (rand-int (dec (count s))))))&lt;/pre&gt;&lt;br /&gt;From which I can take whatever number of random characters I like and do something with, for instance write 100 chars to file as a string:&lt;br /&gt;&lt;pre class="brush :clojure"&gt;(use 'clojure.contrib.duck-streams)&lt;br /&gt;(spit  "data-set.txt"  (apply str (take 100 data-set)))&lt;/pre&gt;&lt;br /&gt;Note that the sequence is cached, so I will get the same characters each time &lt;code&gt;(take 100 ...)&lt;/code&gt;  is called. This may not be what you want. Converting the def to a no-args function, we can call it repeatedly and get different lazy sequences:&lt;br /&gt;&lt;pre class="brush :clojure"&gt;(defn data-set []&lt;br /&gt;  (repeatedly&lt;br /&gt;    #(nth s (rand-int (dec (count s))))))&lt;/pre&gt;&lt;br /&gt;And do:&lt;br /&gt;&lt;pre class="brush: clojure"; first-line: 3&gt;(take 100 (data-set))&lt;/pre&gt;&lt;br /&gt;One final example, a function to calculate the Fibonacci sequence, from &lt;a href="http://en.wikibooks.org/wiki/Clojure_Programming/Examples/Lazy_Fibonacci"&gt;http://en.wikibooks.org/wiki/Clojure_Programming/Examples/Lazy_Fibonacci&lt;/a&gt;:&lt;br /&gt;&lt;pre class="brush: clojure"&gt;(defn fib-seq []&lt;br /&gt;  ((fn rfib [a b] &lt;br /&gt;       (cons a (lazy-seq (rfib b (+ a b)))))&lt;br /&gt;    0 1))&lt;br /&gt;&lt;br /&gt;(take 10 (fib-seq))&lt;/pre&gt;&lt;br /&gt;Gives:&lt;br /&gt;&lt;pre class="brush: clojure; first-line: 7"&gt;(0 1 1 2 3 5 8 13 21 34)&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-1035383527594062259?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/VEP3vq34HIY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/1035383527594062259/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=1035383527594062259" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/1035383527594062259?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/1035383527594062259?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/VEP3vq34HIY/laziness-is-virtue-of-programmer.html" title="Laziness IS a Virtue of a Programmer" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/08/laziness-is-virtue-of-programmer.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEACQH8-fSp7ImA9WxNQEEk.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-9143664688391928212</id><published>2009-06-30T08:49:00.003+02:00</published><updated>2009-09-15T22:32:41.155+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-15T22:32:41.155+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="DDD" /><category scheme="http://www.blogger.com/atom/ns#" term="development" /><category scheme="http://www.blogger.com/atom/ns#" term="citerus" /><title>DDDSample Interview Published</title><content type="html">At &lt;a href="http://www.jfokus.se/"&gt;Jfokus&lt;/a&gt; 2009, Sweden's largest annual Java conference, Peter Backlund and I gave a three-hour tutorial on &lt;a href="http://dddsample.sf.net"/&gt;DDDSample&lt;/a&gt;. DDDSample is a sample application for exploring the building blocks of Domain-Driven Design built in cooperation with Citerus and Eric Evans. &lt;br /&gt;&lt;br /&gt;We were also interviewed by Dan Berg Johnson on the topic; that &lt;a href="http://www.youtube.com/watch?v=wkbT4eu7g7s"&gt;interview is now published&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For more info on Jfokus, including a number of recorded presentations, visit &lt;a href="http://www.jfokus.se/"&gt;http://www.jfokus.se/&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;And don't forget to check out the &lt;a href="http://dddsample.sf.net"/&gt;DDDSample&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-9143664688391928212?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/RwqKtfXg8zo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/9143664688391928212/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=9143664688391928212" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/9143664688391928212?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/9143664688391928212?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/RwqKtfXg8zo/dddsample-interview-published.html" title="DDDSample Interview Published" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/06/dddsample-interview-published.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4ASXo_eip7ImA9WxJWFkU.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-2727390115492300253</id><published>2009-06-22T18:12:00.003+02:00</published><updated>2009-06-22T18:25:48.442+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-22T18:25:48.442+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="psa" /><title>Giving Up on Safari 4</title><content type="html">It lasted 8 days this time around. After using Safari 4 as my main browser for about a week I decided to let it go. Despite applying the &lt;a href="http://weakreference.blogspot.com/2009/06/making-safari-4-usable.html"&gt;tweaks from this post&lt;/a&gt; there are still a few things that just isn't working out for me: &lt;br /&gt;&lt;br /&gt;1) The setting to force opening of new windows in tabs is a little too "always" for my taste. I want (allowed) pop-ups to pop-up, but links that request a new window to be opened in new tabs. I believe this is the Firefox default and it works great.&lt;br /&gt;&lt;br /&gt;2) Blocking pop-up windows is nice, but I'd like the browser to tell me when this happens, so I can elect to view this particular pop-up if I wish,&lt;br /&gt;&lt;br /&gt;3) Once you get used to the Awesomebar, all other URL bars are, well, not so awesome.&lt;br /&gt;&lt;br /&gt;So, for now I am running Firefox 3.5 rc2! If you have any ideas on how to fix the things above, please let me know and perhaps I'll try out Safari 5.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-2727390115492300253?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/YIqKcGrWVFY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/2727390115492300253/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=2727390115492300253" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/2727390115492300253?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/2727390115492300253?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/YIqKcGrWVFY/giving-up-on-safari-4.html" title="Giving Up on Safari 4" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/06/giving-up-on-safari-4.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEECQHs7eSp7ImA9WxJWEkg.&quot;"><id>tag:blogger.com,1999:blog-10486307.post-8595625199234023764</id><published>2009-06-17T08:55:00.006+02:00</published><updated>2009-06-17T18:37:41.501+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-17T18:37:41.501+02:00</app:edited><title>Them Netbooks</title><content type="html">After almost ten years of daily commuting between &lt;a href="http://www.wolframalpha.com/input/?i=uppsala"&gt;Uppsala&lt;/a&gt; and &lt;a href="http://www.wolframalpha.com/input/?i=stockholm"&gt;Stockholm&lt;/a&gt; I finally decided that enough was enough, and moved closer to where I work. For my current engagement this cut traveling down from about 80 to 30 minutest. One way. Per day. Much better from a getting-up-early-and-getting-home-late perspective.&lt;br /&gt;&lt;br /&gt;However, spending all this time on trains had the side-effect of making time available for writing blog entries and PNEHM! articles (and the occasional nap). So with effective train-time cut down from 40 to 18  minutes there simply hasn't been that many blog entries written, except for the occasional &lt;a href="http://weakreference.blogspot.com/search/label/spam"&gt;#spam&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Time is one thing, but the smaller, more crowded city commuter trains, also makes it harder to open a full-size notebook to do writing and reading. So after much angst I decide to get me one of them netbooks. I bought an Asus Eee PC 901 with built in 3G modem, it came originally with Windows XP, but now runs &lt;a href="http://www.eeebuntu.org/"&gt;eeebuntu&lt;/a&gt; 2.0. And it is actually rather nice. Sure, its been hit with the ugly stick, but the total lack of aesthetics is actually somewhat refreshing, the build quality is decent, and you almost get used to the tiny keyboard after a while. It could be a bit more snappy though, so I  am looking forward to trying out eeebutu 3.0 with LXDE, hoping that it will speed things up a bit.&lt;br /&gt;&lt;br /&gt;The 3G mobile connectivity, &lt;a href="http://docs.google.com"&gt;Google Docs&lt;/a&gt;, &lt;a href="http://www.spotify.com/"&gt;Spotify&lt;/a&gt; and the excellent &lt;a href="http://www.getdropbox.com/"&gt;Dropbox&lt;/a&gt; file sharing service gives you pretty much everything you need to write blog entries, catch up on your RSS feeds, browse the web, listen to your favourite music, process e-mails, read e-books, etc. You do your writing on the train, and as you approach the train station you just save and close the lid. As soon as you're back at the office, or home, or wherever, you can easily pick up where you left off, on the same computer or a different one. &lt;br /&gt;&lt;br /&gt;Man, this cloud thing is really great!.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10486307-8595625199234023764?l=weakreference.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheWeakReference/~4/L7lrBj7mdO8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weakreference.blogspot.com/feeds/8595625199234023764/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=10486307&amp;postID=8595625199234023764" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/8595625199234023764?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/10486307/posts/default/8595625199234023764?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TheWeakReference/~3/L7lrBj7mdO8/them-netbooks.html" title="Them Netbooks" /><author><name>Patrik</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://weakreference.blogspot.com/2009/06/them-netbooks.html</feedburner:origLink></entry></feed>

