<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
 
 <title>IMHO</title>
 
 <link href="http://blog.interlinked.org/" />
 <updated>2013-06-13T16:08:45+02:00</updated>
 <id>http://blog.interlinked.org/</id>
 <author>
   <name>Michael Jakl</name>
   <email>interlinked.org@gmail.com</email>
 </author>

 
 <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/IMHO" /><feedburner:info uri="imho" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
   <title>The Most Amazing PostgreSQL Database</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/Ze5pVChd6OA/postgresql.html" />
   <updated>2012-10-07T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/tutorials/postgresql</id>
   <content type="html">&lt;p&gt;For me PostgreSQL is the most amazing (open source) database around. Even
though, there is much interest in stripped down NoSQL databases like key-value
stores or “data structure servers”, PostgreSQL continues to innovate at the
SQL frontier.&lt;/p&gt;

&lt;p&gt;In this post, I’ll show a few of the newer, less known, features of PostgreSQL
- far beyond standard SQL.&lt;/p&gt;

&lt;h2 id="hstore"&gt;hstore&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.postgresql.org/docs/9.1/static/hstore.html"&gt;hstore&lt;/a&gt; is a key-value
store for simple data types. Using hstore, we’re able to create a key-value store
within columns of a table.&lt;/p&gt;

&lt;p&gt;To enable the hstore extension, run &lt;code&gt;create extension hstore'&lt;/code&gt; in the
PostgreSQL prompt. After that the &lt;code&gt;hstore&lt;/code&gt; data type is available for our
table definitions.&lt;/p&gt;

&lt;p&gt;Let’s create a simple table with a hstore column:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;create table hstoretest ( id serial primary key, data hstore );
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To insert a few rows, we use a special syntax:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;insert into hstoretest (data) values ('key1 =&amp;gt; 123, key2 =&amp;gt; "text"'::hstore);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Query the table as usual:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;select * from hstoretest;

 id |                           data
----+-----------------------------------------------------------
  1 | "key1"=&amp;gt;"123", "key2"=&amp;gt;"text"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The hstore extension provides a lot of operators and functions to work with
hstore columns, for example, selecting all &lt;code&gt;key2&lt;/code&gt; values:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;select data -&amp;gt; 'key2' as key2 from hstoretest;

 key2
------
 text
(1 row)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Some more examples can be found &lt;a href="http://www.youlikeprogramming.com/2011/11/working-with-the-hstore-data-type-in-postgresql-9-0/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="json"&gt;JSON&lt;/h2&gt;

&lt;p&gt;A &lt;a href="http://www.postgresql.org/docs/9.2/static/datatype-json.html"&gt;JSON data type&lt;/a&gt; was
introduced in release 9.2. Currently this is nothing more than a validating
data type, thus it checks if the string we put into that column is a valid
JSON object.&lt;/p&gt;

&lt;p&gt;Let’s create a new table to play around with this type:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;create table jsontest ( id serial primary key, data json );
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now let’s insert an invalid row:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;insert into jsontest (data) values ('{"title":wrong}');

ERROR:  invalid input syntax for type json
LINE 1: insert into jsontest (data) values ('{"title":wrong}');
                                            ^
DETAIL:  Token "wrong" is invalid.
CONTEXT:  JSON data, line 1: {"title":wrong...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now with the correct JSON syntax:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;insert into jsontest (data) values ('{"title":"right"}');
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There isn’t really much more to the JSON data type besides the ability to
return rows of non-JSON tables as JSON:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;select row_to_json(hstoretest) from hstoretest;

                                       row_to_json
-----------------------------------------------------------------------------------------
 {"id":1,"data":"\"key1\"=&amp;gt;\"123\", \"key2\"=&amp;gt;\"text\""}
(1 row)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nice if you’re used to work with JSON object (in Web applications for
example).&lt;/p&gt;

&lt;h3 id="plv8"&gt;PLv8&lt;/h3&gt;

&lt;p&gt;Working directly with JSON and JavaScript has been all the rage in many of the
NoSQL databases. Using the &lt;a href="https://code.google.com/p/plv8js/"&gt;PLv8 extension&lt;/a&gt;,
we can use JavaScript (executed by Google’s awesome V8 engine) directly in PostgreSQL.
Together with the JSON data type, this offers amazing new possibilities.&lt;/p&gt;

&lt;p&gt;Currently PLv8 isn’t included in the standard distribution of PostgreSQL
(9.2), but installing it isn’t very hard, the only dependencies are postgresql
and the v8 engine. Some distributions already have v8 in their repositories
(&lt;a href="http://www.archlinux.org/packages/community/x86_64/v8/"&gt;Archlinux&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Compiling and installing the extension is straight forward as soon as the
dependencies are in place:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;make &amp;amp;&amp;amp; sudo make install
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;No we can enable the plv8 extension within our database (as we did with hstore):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;create extension plv8;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A particular nice example of using JSON and PLv8 comes from &lt;a href="http://people.planetpostgresql.org/andrew/index.php?/archives/249-Using-PLV8-to-index-JSON.html"&gt;Andrew Dunstan&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;create or replace function jmember (j json, key text )
 RETURNS text
 LANGUAGE plv8
 IMMUTABLE
AS $function$
  var ej = JSON.parse(j);
  if (typeof ej != 'object')
        return NULL;
  return JSON.stringify(ej[key]);
$function$;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;jmember&lt;/code&gt; function allows us to parse and read the JSON string and returns
the member identified by &lt;code&gt;key&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;select jmember(data, 'title') from jsontest;

     jmember
-----------------
 "right"
(1 row)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Andrew also shows how to build an index to speed up access times in his post.&lt;/p&gt;

&lt;h2 id="k-nearest-neighbors"&gt;k-Nearest Neighbors&lt;/h2&gt;

&lt;p&gt;In PostgreSQL 9.1, a &lt;a href="http://wiki.postgresql.org/wiki/What's_new_in_PostgreSQL_9.1"&gt;nearest neighbor
indexing&lt;/a&gt; was
introduced. This allows us to perform orderings etc. by a distance metric.&lt;/p&gt;

&lt;p&gt;For example, I’ve downloaded the &lt;a href="http://wordlist.sourceforge.net/"&gt;ispell spelling
dictionaries&lt;/a&gt;, and loaded them into a table
&lt;code&gt;words&lt;/code&gt; like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;create table words (word varchar(50) primary key);
copy words from 'english.0';
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This inserts roughly 50000 words into the table.&lt;/p&gt;

&lt;p&gt;Since we’re working with text data, let’s introduce another extension
&lt;code&gt;pg_trgm&lt;/code&gt;, which builds tri-grams of strings (triples of three characters).
Using theses tri-grams, we can compute a distance metric. Enable the extension
like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;create extension pg_trgm;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A tri-gram of &lt;code&gt;hello&lt;/code&gt; would look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;select show_trgm('hello');
            show_trgm
---------------------------------
 {"  h"," he",ell,hel,llo,"lo "}
(1 row)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The distance metric is very simple, the more of these tri-grams match, the
closer two strings are.&lt;/p&gt;

&lt;p&gt;To take advantage of the nearest neighbor index, we have to build it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;create index word_trgm_idx on words using gist (word gist_trgm_ops);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Using the index we can query our table for a word, and return a list of most
similar terms as well:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;select word, word &amp;lt;-&amp;gt; 'hello' as distance from words order by word &amp;lt;-&amp;gt; 'hello' asc limit 10;
  word  | distance
--------+----------
 hello  |        0
 hellos |    0.375
 hell   | 0.428571
 hells  |      0.5
 heller | 0.555556
 hell's | 0.555556
 help   |    0.625
 helm   |    0.625
 held   |    0.625
 helps  | 0.666667
(10 rows)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;-&amp;gt;&lt;/code&gt; operator comes from the &lt;code&gt;pg_trgm&lt;/code&gt; extension, of course we could use
simpler distances like numerical difference or geometric distance, but working
with textual data is often perceived as particularly difficult (not so with
PostgreSQL).&lt;/p&gt;

&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/Ze5pVChd6OA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/postgresql.html</feedburner:origLink></entry>
 
 <entry>
   <title>A REST API in Clojure</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/bKuZQP0E49I/clojure_rest.html" />
   <updated>2012-10-04T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/clojure_rest</id>
   <content type="html">&lt;p&gt;Clojure is one of the most interesting new languages targeting the JVM.
Initially only the JVM, in the meantime it is also available for JavaScript.
Essentially, you can write Clojure and either execute it as Java program or
JavaScript program, of course each flavor has its unique features as well.&lt;/p&gt;

&lt;p&gt;Clojure is a Lisp, thus the syntax may be foreign, but it is really, really
easy since there are very few syntactic variations. The language “Lisp” is
very lean and usually easily learned.&lt;/p&gt;

&lt;p&gt;In this post, we’re going to create a complete REST application from scratch.
There are already some (very) good tutorials available, but some are not quite
up to date (see
&lt;a href="https://devcenter.heroku.com/articles/clojure-web-application"&gt;Heroku’s Devcenter&lt;/a&gt;
or &lt;a href="http://mmcgrana.github.com/2010/08/clojure-rest-api.html"&gt;Mark McGranaghan&lt;/a&gt;
for good ones). Clojure itself is still a young language, Lisp of
course has a lot of history.&lt;/p&gt;

&lt;p&gt;Our application should allow creating, listing, fetching, updating, and
deleting of documents.&lt;/p&gt;

&lt;p&gt;A document looks like this (JSON encoded):&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="json"&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;some id&amp;quot;&lt;/span&gt;
      &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;title&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;some title&amp;quot;&lt;/span&gt;
      &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;some text&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;A &lt;code&gt;GET&lt;/code&gt; call to &lt;code&gt;/documents&lt;/code&gt; should return a list of these documents.&lt;/li&gt;
  &lt;li&gt;A &lt;code&gt;POST&lt;/code&gt; call to &lt;code&gt;/documents&lt;/code&gt; with a documents as body shall create a new
 document, assigning a new &lt;code&gt;id&lt;/code&gt; (ignoreing the posted one).&lt;/li&gt;
  &lt;li&gt;A &lt;code&gt;GET&lt;/code&gt; to &lt;code&gt;/documents/[ID]&lt;/code&gt; should return the document with the given &lt;code&gt;id&lt;/code&gt;, or
 &lt;code&gt;404&lt;/code&gt; if the document does not exist.&lt;/li&gt;
  &lt;li&gt;A &lt;code&gt;PUT&lt;/code&gt; to &lt;code&gt;/documents/[ID]&lt;/code&gt; should update the document with the given &lt;code&gt;id&lt;/code&gt; and
 replace &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt; with those from the document in the uploaded body.&lt;/li&gt;
  &lt;li&gt;A &lt;code&gt;DELETE&lt;/code&gt; to &lt;code&gt;/documents/[ID]&lt;/code&gt; should delete the document with the given &lt;code&gt;id&lt;/code&gt;
 and return 204 (NO CONTENT) in any case.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="creating-the-project-scaffolding"&gt;Creating the project scaffolding&lt;/h2&gt;

&lt;p&gt;We’re going to use &lt;a href="http://leiningen.org"&gt;Leiningen&lt;/a&gt;, the defacto build
system and dependency manager for Clojure projects. Download and install it,
then execute:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="sh"&gt;    lein new compojure clojure-rest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We’re creating a new &lt;a href="http://compojure.org"&gt;Compojure&lt;/a&gt; project called
&lt;code&gt;clojure-rest&lt;/code&gt;. Compojure is the library that maps URLs to functions in our
program. Compojure (and our project) builds on
&lt;a href="https://github.com/ring-clojure/ring"&gt;Ring&lt;/a&gt; is the basic Server API. To start
the new project run:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="sh"&gt;    lein ring server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This starts the server on &lt;a href="http://localhost:3000"&gt;localhost:3000&lt;/a&gt; and
automatically restarts the server if any of the project files change. Thus,
you can leave it running while we develop our application.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;new&lt;/code&gt; command generates two very important files for us:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;project.clj&lt;/code&gt; is the project configuration. It states dependencies, the entry
point etc. (read the whole documentation on &lt;a href="http://leiningen.org"&gt;Leiningen.org&lt;/a&gt;,
and &lt;code&gt;src/clojure_rest/handler.clj&lt;/code&gt; which contains a starting point for our application.&lt;/p&gt;

&lt;h2 id="project-configuration-projectclj"&gt;Project configuration (project.clj)&lt;/h2&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defproject &lt;/span&gt;&lt;span class="nv"&gt;clojure-rest&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.1.0-SNAPSHOT&amp;quot;&lt;/span&gt;
      &lt;span class="ss"&gt;:description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;FIXME: write description&amp;quot;&lt;/span&gt;
      &lt;span class="ss"&gt;:url&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;http://example.com/FIXME&amp;quot;&lt;/span&gt;
      &lt;span class="ss"&gt;:dependencies&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;org.clojure/clojure&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1.4.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1.1.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
      &lt;span class="ss"&gt;:plugins&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;lein-ring&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.7.3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
      &lt;span class="ss"&gt;:ring&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:handler&lt;/span&gt; &lt;span class="nv"&gt;clojure-rest.handler/app&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="ss"&gt;:profiles&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:dependencies&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;ring-mock&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.1.3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]}})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Update the file to look like this:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defproject &lt;/span&gt;&lt;span class="nv"&gt;clojure-rest&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.1.0-SNAPSHOT&amp;quot;&lt;/span&gt;
      &lt;span class="ss"&gt;:description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;REST service for documents&amp;quot;&lt;/span&gt;
      &lt;span class="ss"&gt;:url&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;http://blog.interlinked.org&amp;quot;&lt;/span&gt;
      &lt;span class="ss"&gt;:dependencies&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;org.clojure/clojure&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1.4.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1.1.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring/ring-json&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.1.2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;c3p0/c3p0&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.9.1.2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;org.clojure/java.jdbc&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.2.3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;com.h2database/h2&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1.3.168&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;cheshire&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;4.0.3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
      &lt;span class="ss"&gt;:plugins&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;lein-ring&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.7.3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
      &lt;span class="ss"&gt;:ring&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:handler&lt;/span&gt; &lt;span class="nv"&gt;clojure-rest.handler/app&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="ss"&gt;:profiles&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:dev&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:dependencies&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;ring-mock&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.1.3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]}})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Besides the JSON parsing library
&lt;a href="https://github.com/dakrone/cheshire"&gt;Cheshire&lt;/a&gt;, we added the &lt;a href="http://sourceforge.net/projects/c3p0/"&gt;C3P0 Connection
Pool&lt;/a&gt;, the &lt;a href="http://h2database.com"&gt;H2
Database&lt;/a&gt; JDBC driver and Clojure’s
&lt;a href="https://github.com/clojure/java.jdbc"&gt;java.jdbc&lt;/a&gt; contrib-library.&lt;/p&gt;

&lt;p&gt;I also updated the &lt;code&gt;:url&lt;/code&gt; and &lt;code&gt;:description&lt;/code&gt; fields.&lt;/p&gt;

&lt;h2 id="the-request-handler-handlerclj"&gt;The request handler (handler.clj)&lt;/h2&gt;

&lt;p&gt;Next let’s have a look at the generated request handler
&lt;code&gt;src/clojure_rest/handler.clj&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;ns &lt;/span&gt;&lt;span class="nv"&gt;clojure-rest.handler&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:use&lt;/span&gt; &lt;span class="nv"&gt;compojure.core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure.handler&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure.route&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;route&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt; &lt;span class="nv"&gt;app-routes&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route/not-found&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Not Found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handler/site&lt;/span&gt; &lt;span class="nv"&gt;app-routes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The route &lt;code&gt;GET "/" [] "Hello World"&lt;/code&gt; is responsible for our result we saw in
the browser. It maps all GET requests to &lt;code&gt;/&lt;/code&gt; without parameters to &lt;code&gt;"Hello
World"&lt;/code&gt;. The &lt;code&gt;(def app (handler/site app-routes))&lt;/code&gt; part configures our
application (registering the routes).&lt;/p&gt;

&lt;p&gt;Our first step is to update the configuration. We’re going to work with JSON,
so let’s include some Ring middlewares to setup response headers
(&lt;code&gt;wrap-json-response&lt;/code&gt;) and parse request bodies (&lt;code&gt;wrap-json-body&lt;/code&gt;) for us.
A middleware is just a wrapper around a handler, thus it can pre- and
post-process the whole request/response cycle.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handler/api&lt;/span&gt; &lt;span class="nv"&gt;app-routes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;middleware/wrap-json-body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;middleware/wrap-json-response&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We switched also from the &lt;code&gt;handler/site&lt;/code&gt; template to &lt;code&gt;handler/api&lt;/code&gt; which is
more appropriate for REST APIs (&lt;a href="http://weavejester.github.com/compojure/compojure.handler.html"&gt;documentation&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Next let’s define the routes for our application:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt; &lt;span class="nv"&gt;app-routes&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;context&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/documents&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt; &lt;span class="nv"&gt;documents-routes&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;  &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-all-documents&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;body&lt;/span&gt; &lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;create-new-document&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;context&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/:id&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt; &lt;span class="nv"&gt;document-routes&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;    &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-document&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;PUT&lt;/span&gt;    &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;body&lt;/span&gt; &lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;update-document&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;DELETE&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delete-document&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route/not-found&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Not Found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We define GET and POST for the &lt;code&gt;context "/documents&lt;/code&gt;, and GET, PUT, DELETE for
the &lt;code&gt;context ":id"&lt;/code&gt; on top of that. &lt;code&gt;:id&lt;/code&gt; is a placeholder and can then be
injected into our parameter vector. The POST and PUT request have a special
parameter &lt;code&gt;body&lt;/code&gt; for the parsed body (this parameter is provided by the
&lt;code&gt;wrap-json-body&lt;/code&gt; middleware. For more on routes, take a look at &lt;a href="https://github.com/weavejester/compojure/wiki/Routes-In-Detail"&gt;Compojure’s
documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before we define the functions to carry out the requests, let’s fix the
imports and open a pool of database connections to work with.&lt;/p&gt;

&lt;p&gt;The namespace declaration is used to define which namespaces shall be made
available by Clojure.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;ns &lt;/span&gt;&lt;span class="nv"&gt;clojure-rest.handler&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:import&lt;/span&gt; &lt;span class="nv"&gt;com.mchange.v2.c3p0.ComboPooledDataSource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:use&lt;/span&gt; &lt;span class="nv"&gt;compojure.core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:use&lt;/span&gt; &lt;span class="nv"&gt;cheshire.core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:use&lt;/span&gt; &lt;span class="nv"&gt;ring.util.response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure.handler&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring.middleware.json&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;clojure.java.jdbc&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure.route&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;route&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We import C3P0’s &lt;code&gt;ComboPooledDataSource&lt;/code&gt;, a plain Java class. Next, we fetch
the functions defined in &lt;code&gt;compojure.core&lt;/code&gt;, &lt;code&gt;cheshire.core&lt;/code&gt;, and
&lt;code&gt;ring.util.response&lt;/code&gt; into our namespace, they can be used without qualifying.
Finally we require some more libraries, this time with a qualifier to prevent
name clashes or to support nicer separation. I’m not sure when to make the cut
between &lt;code&gt;:use&lt;/code&gt; and &lt;code&gt;:require&lt;/code&gt; yet, so the cut is abitrary.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;db-config&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:classname&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;org.h2.Driver&amp;quot;&lt;/span&gt;
       &lt;span class="ss"&gt;:subprotocol&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;h2&amp;quot;&lt;/span&gt;
       &lt;span class="ss"&gt;:subname&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;mem:documents&amp;quot;&lt;/span&gt;
       &lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
       &lt;span class="ss"&gt;:password&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note, we use a in-memory database. If you’d like to keep your database between
restarts, you could use &lt;code&gt;:subname "/tmp/documents"&lt;/code&gt; for example.&lt;/p&gt;

&lt;p&gt;Next we open a pool of connections. C3P0 has no Clojure wrapper, so we deal
with Java classes and objects directly (hence a bit more code).&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;pool&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;cpds&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;doto &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ComboPooledDataSource.&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setDriverClass&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:classname&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setJdbcUrl&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;jdbc:&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:subprotocol&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:subname&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setUser&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setPassword&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setMaxPoolSize&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setMinPoolSize&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setInitialPoolSize&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:datasource&lt;/span&gt; &lt;span class="nv"&gt;cpds&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;pooled-db&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delay&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;pool&lt;/span&gt; &lt;span class="nv"&gt;db-config&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;db-connection&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;pooled-db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since we deal with a in-memory database, we need to create our table now.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-connection&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;db-connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/create-table&lt;/span&gt; &lt;span class="ss"&gt;:documents&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;varchar(256)&amp;quot;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;primary key&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                                   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;varchar(1024)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                                   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt; &lt;span class="ss"&gt;:varchar&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The intent should be easy to understand, for the details take a look at the
&lt;a href="http://clojure.github.com/java.jdbc/"&gt;java.jdbc documentation&lt;/a&gt;. We create a
table &lt;code&gt;documents&lt;/code&gt; with a &lt;code&gt;:id&lt;/code&gt;, &lt;code&gt;:title&lt;/code&gt;, and &lt;code&gt;:text&lt;/code&gt; column. Note that the
database column is called &lt;code&gt;id&lt;/code&gt;, not &lt;code&gt;:id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The only thing missing are the functions to actually perform the actions
requested by our clients.&lt;/p&gt;

&lt;p&gt;To return a single document with a given &lt;code&gt;id&lt;/code&gt;, we could come up with this:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;get-document&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-connection&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;db-connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-query-results&lt;/span&gt; &lt;span class="nv"&gt;results&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;select * from documents where id = ?&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cond&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt; &lt;span class="nv"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:status&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="ss"&gt;:else&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;results&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It reads like this: when called with an &lt;code&gt;id&lt;/code&gt;, open a database connection,
perform &lt;code&gt;select * from documents where id = ?&lt;/code&gt; with the given &lt;code&gt;id&lt;/code&gt; as
parameter. If the result is empty, return &lt;code&gt;404&lt;/code&gt;, otherwise return the first
(and only) document as response.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;response&lt;/code&gt; call will convert the document into JSON, this functionality is
provided by &lt;code&gt;wrap-json-response&lt;/code&gt;, which also sets the correct &lt;code&gt;Content-Type&lt;/code&gt;
etc.&lt;/p&gt;

&lt;p&gt;Another nice one is the creation of new documents:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;uuid&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;java.util.UUID/randomUUID&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;create-new-document&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-connection&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;db-connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;document&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;assoc doc &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/insert-record&lt;/span&gt; &lt;span class="ss"&gt;:documents&lt;/span&gt; &lt;span class="nv"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-document&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here we use Java’s UUID generator (without import, hence the full package
name) to generate a new &lt;code&gt;id&lt;/code&gt; for each document created. The second &lt;code&gt;let&lt;/code&gt;
statement is responsible to replace the user-provided &lt;code&gt;id&lt;/code&gt; (if any) with our
generated one. Remember that Clojure’s datastructures are immutable, so we
need to use the &lt;code&gt;document&lt;/code&gt; variable thereafter, instead of the &lt;code&gt;doc&lt;/code&gt; which
still contains the old (or no) &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Returning the document is delegated to the &lt;code&gt;get-document&lt;/code&gt; function.&lt;/p&gt;

&lt;h3 id="the-complete-handlerclj"&gt;The complete handler.clj&lt;/h3&gt;

&lt;p&gt;To round the post up, here is the whole program:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="clojure"&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;ns &lt;/span&gt;&lt;span class="nv"&gt;clojure-rest.handler&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:import&lt;/span&gt; &lt;span class="nv"&gt;com.mchange.v2.c3p0.ComboPooledDataSource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:use&lt;/span&gt; &lt;span class="nv"&gt;compojure.core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:use&lt;/span&gt; &lt;span class="nv"&gt;cheshire.core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:use&lt;/span&gt; &lt;span class="nv"&gt;ring.util.response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure.handler&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring.middleware.json&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;clojure.java.jdbc&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure.route&lt;/span&gt; &lt;span class="ss"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;route&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;db-config&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:classname&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;org.h2.Driver&amp;quot;&lt;/span&gt;
       &lt;span class="ss"&gt;:subprotocol&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;h2&amp;quot;&lt;/span&gt;
       &lt;span class="ss"&gt;:subname&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;mem:documents&amp;quot;&lt;/span&gt;
       &lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
       &lt;span class="ss"&gt;:password&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;pool&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;cpds&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;doto &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ComboPooledDataSource.&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setDriverClass&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:classname&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setJdbcUrl&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;jdbc:&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:subprotocol&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:subname&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setUser&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setPassword&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setMaxPoolSize&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setMinPoolSize&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.setInitialPoolSize&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:datasource&lt;/span&gt; &lt;span class="nv"&gt;cpds&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;pooled-db&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delay&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;pool&lt;/span&gt; &lt;span class="nv"&gt;db-config&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;db-connection&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;pooled-db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-connection&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;db-connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;;  (sql/drop-table :documents) ; no need to do that for in-memory databases&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/create-table&lt;/span&gt; &lt;span class="ss"&gt;:documents&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;varchar(256)&amp;quot;&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;primary key&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                                   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;varchar(1024)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                                   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt; &lt;span class="ss"&gt;:varchar&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;uuid&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;java.util.UUID/randomUUID&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;get-all-documents&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-connection&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;db-connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-query-results&lt;/span&gt; &lt;span class="nv"&gt;results&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;select * from documents&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;into &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nv"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;get-document&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-connection&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;db-connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-query-results&lt;/span&gt; &lt;span class="nv"&gt;results&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;select * from documents where id = ?&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cond&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt; &lt;span class="nv"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:status&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="ss"&gt;:else&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;results&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;create-new-document&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-connection&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;db-connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;document&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;assoc doc &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/insert-record&lt;/span&gt; &lt;span class="ss"&gt;:documents&lt;/span&gt; &lt;span class="nv"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-document&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;update-document&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="nv"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-connection&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;db-connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;document&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;assoc doc &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/update-values&lt;/span&gt; &lt;span class="ss"&gt;:documents&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id=?&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nv"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-document&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;delete-document&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/with-connection&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;db-connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sql/delete-rows&lt;/span&gt; &lt;span class="ss"&gt;:documents&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id=?&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:status&lt;/span&gt; &lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt; &lt;span class="nv"&gt;app-routes&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;context&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/documents&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt; &lt;span class="nv"&gt;documents-routes&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;  &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-all-documents&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;body&lt;/span&gt; &lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;create-new-document&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;context&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/:id&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt; &lt;span class="nv"&gt;document-routes&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;    &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-document&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;PUT&lt;/span&gt;    &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;body&lt;/span&gt; &lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;update-document&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;DELETE&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delete-document&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route/not-found&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Not Found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def &lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handler/api&lt;/span&gt; &lt;span class="nv"&gt;app-routes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;middleware/wrap-json-body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;middleware/wrap-json-response&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Yeah, the whole program with connection pooling, JSON de/encoding in roughly
90 lines of (admittedly dense) code.&lt;/p&gt;

&lt;p&gt;To sum it up: Clojure is fun, concise, and very powerful. Together with the
excellent Java integration it ranks very high on my “languages I adore” list.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/bKuZQP0E49I" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/clojure_rest.html</feedburner:origLink></entry>
 
 <entry>
   <title>REST Framework Survey (Java, Haskell, Go, Node.js)</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/y2qhWV30heY/rest_frameworks.html" />
   <updated>2012-09-23T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/rest_frameworks</id>
   <content type="html">&lt;p&gt;Over the last few days I’ve experimented with various REST frameworks. The
initial goal was to find &lt;em&gt;The Language&lt;/em&gt; and framework to use for all future
projects… . Of course there is no clear winner.&lt;/p&gt;

&lt;p&gt;These were the contestants:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://nodejs.org/"&gt;Node.js&lt;/a&gt; with &lt;a href="http://mcavage.github.com/node-restify/"&gt;Restify&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.java.com"&gt;Java&lt;/a&gt; with &lt;a href="http://jersey.java.net/"&gt;Jersey&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.haskell.org"&gt;Haskell&lt;/a&gt; with &lt;a href="https://github.com/xich/scotty"&gt;Scotty&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The client was written in &lt;a href="http://www.golang.org"&gt;Go&lt;/a&gt; because I wanted &lt;del&gt;it to
be fast and easy to make concurrent requests&lt;/del&gt; to try Go.&lt;/p&gt;

&lt;p&gt;The server spec is to povide a way to insert, query, update, list and delete
documents.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A &lt;code&gt;POST&lt;/code&gt; to &lt;code&gt;/documents&lt;/code&gt; should create a new document, generate a new UUID (v4) as ID and return the whole document.&lt;/li&gt;
  &lt;li&gt;A &lt;code&gt;GET&lt;/code&gt; to &lt;code&gt;/documents&lt;/code&gt; should return a list of all documents&lt;/li&gt;
  &lt;li&gt;A &lt;code&gt;GET&lt;/code&gt; to &lt;code&gt;/documents/[ID]&lt;/code&gt; should return the document with the given ID, or 404 if it is not found.&lt;/li&gt;
  &lt;li&gt;A &lt;code&gt;PUT&lt;/code&gt; to &lt;code&gt;/documents/[ID]&lt;/code&gt; should update the document with the given ID and return it.&lt;/li&gt;
  &lt;li&gt;A &lt;code&gt;DELETE&lt;/code&gt; to &lt;code&gt;/documents/[ID]&lt;/code&gt; should delete the document with the given ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The documents are encoded in &lt;a href="http://www.json.org/"&gt;JSON&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
    "id": "some id",
    "title": "some title",
    "text": "some text"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The client may or may not send the &lt;code&gt;id&lt;/code&gt; field, the server ignores it and either
generates a new one, or uses the one from the URL.&lt;/p&gt;

&lt;p&gt;The client’s steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Insert a document&lt;/li&gt;
  &lt;li&gt;Update that document&lt;/li&gt;
  &lt;li&gt;Delete that document&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I used &lt;code&gt;goroutines&lt;/code&gt; to make that concurrent and checked the consistency via a
final &lt;code&gt;GET /documents&lt;/code&gt; asserting an empty list.&lt;/p&gt;

&lt;h2 id="step-1"&gt;Step 1&lt;/h2&gt;

&lt;p&gt;As database backend, I used an &lt;a href="http://www.sqlite.org/"&gt;SQLite3&lt;/a&gt; in-memory database connected via:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://github.com/developmentseed/node-sqlite3"&gt;node-sqlite3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.xerial.org/trac/Xerial/wiki/SQLiteJDBC"&gt;SQLiteJDBC&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://hackage.haskell.org/package/HDBC-sqlite3"&gt;HDBC-sqlite3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implementation was easy with Java and Node.js. I’ve had my fair share of
trouble with Haskell because there is no clear REST framework to use, at least
I couldn’t find the obvious choice and went with Scotty because it’s simple
and did what I needed, and my Haskell-fu has seen better days.&lt;/p&gt;

&lt;p&gt;Here’s a inconclusive performance report&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt; (how long it took, in seconds, so
&lt;em&gt;longer is worse&lt;/em&gt;) processing 10000 documents with the &lt;em&gt;same&lt;/em&gt; client
on each of the backends.&lt;/p&gt;

&lt;script type="text/javascript+protovis"&gt;
var drawchart = function(data, titles) {
  var w = 800,
      h = data.length * 25,
      x = pv.Scale.linear(0, Math.max.apply(Math, data) * 1.1).range(0, w),
      y = pv.Scale.ordinal(pv.range(data.length)).splitBanded(0, h, 4/5);

  /* The root panel. */
  var vis = new pv.Panel()
      .width(w)
      .height(h)
      .bottom(20)
      .left(70)
      .right(10)
      .top(5);

  /* The bars. */
  var bar = vis.add(pv.Bar)
      .data(data)
      .top(function() y(this.index))
      .height(y.range().band)
      .left(0)
      .width(x);

  /* The value label. */
  bar.anchor("right").add(pv.Label)
      .textStyle("white")
      .text(function(d) d.toFixed(1));

  /* The variable label. */
  bar.anchor("left").add(pv.Label)
      .textMargin(5)
      .textAlign("right")
      .text(function() titles[this.index]);

  /* X-axis ticks. */
  vis.add(pv.Rule)
      .data(x.ticks(5))
      .left(x)
      .strokeStyle(function(d) d ? "rgba(255,255,255,.3)" : "#000")
    .add(pv.Rule)
      .bottom(0)
      .height(5)
      .strokeStyle("#000")
    .anchor("bottom").add(pv.Label)
      .text(x.tickFormat);

  return vis;
};
&lt;/script&gt;

&lt;script type="text/javascript+protovis"&gt;
drawchart([
      16.71,
      12.34,
      11.84
    ], [
      "Node.js",
      "Java",
      "Haskell"
    ]
).render();
&lt;/script&gt;

&lt;p&gt;Node.js is a bit slower, Java and Haskell are pretty much on par.&lt;/p&gt;

&lt;h3 id="code"&gt;Code&lt;/h3&gt;

&lt;p&gt;Here’s the code used to update (&lt;code&gt;PUT&lt;/code&gt;) the new version of a document on the
server. I’ve chosen the update case because it shows how to deal with
path-parameters, as well as how to decode and encode JSON.&lt;/p&gt;

&lt;p&gt;Node.js Code to wire &lt;code&gt;PUT&lt;/code&gt; requests to the DB.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="javascript"&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/documents/:docId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// define which function to call for that URL+method&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// directly available as object through the BodyParser plugin&lt;/span&gt;
  &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;docId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// taken from the URL&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;update documents set title = ?, text = ? where id = ?&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// read the document or return 404&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The Jersey annotations used to declare “updateDocument” as handler for &lt;code&gt;PUT&lt;/code&gt;
requests. JSON en/decoding is fully transparent (because of the &lt;code&gt;@Produces&lt;/code&gt;
annotation).&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@PUT&lt;/span&gt; &lt;span class="c1"&gt;// handle PUT requests&lt;/span&gt;
&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/documents/{id}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// on that URL&lt;/span&gt;
&lt;span class="nd"&gt;@Consumes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// accepts only JSON&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// writes out JSON&lt;/span&gt;
&lt;span class="c1"&gt;// params can be references and injected, the body is automaticall decoded into the correct object&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Document&lt;/span&gt; &lt;span class="nf"&gt;updateDocument&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="n"&gt;SQLException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// perform the database stuff (in a data access object as it is customary in Java)&lt;/span&gt;
    &lt;span class="n"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;documentDao&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotFoundException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// produces the 404 status&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// the returned object is also automatically encoded&lt;/span&gt;
    &lt;span class="c1"&gt;// and all headers are set correctly&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The Haskell version is very concise, but with the various Monad-layerings a bit
opaque (especially the DB code):&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="haskell"&gt;&lt;span class="nf"&gt;put&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/documents/:id&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt; &lt;span class="c1"&gt;-- the URL this function is defined for&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class="c1"&gt;-- extract the parameter from the URL&lt;/span&gt;
  &lt;span class="n"&gt;inputDocument&lt;/span&gt; &lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;jsonData&lt;/span&gt; &lt;span class="c1"&gt;-- parse the JSON body&lt;/span&gt;
  &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="ow"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;liftIO&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;updateDocument&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;inputDocument&lt;/span&gt; &lt;span class="c1"&gt;-- write the stuff into the DB&lt;/span&gt;
  &lt;span class="n"&gt;resultOr404&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="c1"&gt;-- return the document or 404&lt;/span&gt;

&lt;span class="c1"&gt;-- for reference on how to deal with Maybe&lt;/span&gt;
&lt;span class="nf"&gt;resultOr404&lt;/span&gt; &lt;span class="ow"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="kt"&gt;Document&lt;/span&gt; &lt;span class="ow"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;ActionM&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;resultOr404&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt;  &lt;span class="ow"&gt;=&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="n"&gt;status404&lt;/span&gt; &lt;span class="c1"&gt;-- return 404 without a body&lt;/span&gt;
&lt;span class="nf"&gt;resultOr404&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="c1"&gt;-- return JSON (also setting the content type)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Actually, the only server checking for the existance of the document is the
Haskell variant. Simply because the type system enforces it!&lt;/p&gt;

&lt;p&gt;Finally, here is the corresponding Go client code:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="go"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nx"&gt;updateDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;New Title&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;New Text&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// set the new content&lt;/span&gt;
    &lt;span class="nx"&gt;jsonReader&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;getJsonReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// encode into JSON&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;PUT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsonReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// prepare the call&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsonType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// set the correct content-type&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// execute the call&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// check for a response&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// close the response stream&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// yeah, I ignore errors...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="step-2"&gt;Step 2&lt;/h2&gt;

&lt;p&gt;After trying out the services with the in-memory database, I got curious and
wanted to see how they’d perform using a &lt;a href="http://www.postgresql.org/"&gt;PostgreSQL
Database&lt;/a&gt;. So I switched the database layer to
these:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://github.com/brianc/node-postgres"&gt;node-postgres&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://jdbc.postgresql.org/"&gt;pgJDBC&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://hackage.haskell.org/package/HDBC-postgresql"&gt;HDBC-postgresql&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The switch was pretty easy for Java and Haskell (a matter of exchanging the
database driver and connect-string). For Node.js I had to rewrite more or less
the whole app since there seems to be no standard interface for DB access.&lt;/p&gt;

&lt;p&gt;The client does not need to change.&lt;/p&gt;

&lt;p&gt;The performance of the REST services with Postgres instead of SQLite are shown
below. This time they show the time needed to process 1000 documents. I wasn’t
patient enough to wait for 10000 documents to finish – I took the
average of three runs.&lt;/p&gt;

&lt;script type="text/javascript+protovis"&gt;
drawchart([
      1.64,
      8.35,
      2.58
    ], [
      "Node.js",
      "Java",
      "Haskell"
    ]
).render();
&lt;/script&gt;

&lt;p&gt;This time, Node blew Java away, Haskell was also significantly slower than
Node. My guess is, that the JDBC and HDBC abstractions take their fair share of
overhead, but Java’s extreme case might have another cause (I haven’t
investigated here).&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;h4 id="writing-v1"&gt;Writing v1&lt;/h4&gt;

&lt;p&gt;In general, writing the server in Java was quite easy (I’m used to that),
Node.js was easy too (chaning was hard), and Haskell took me more time than
the other two servers and the Go client together.  I’d love to add Clojure
and a Go server to the mix and see how they perform.&lt;/p&gt;

&lt;p&gt;All three contestants work well and are reasonably fast. I never noticed Java’s
problem with Postgres as shown here, but I rarely use JDBC directly these days.&lt;/p&gt;

&lt;h4 id="update-to-v2"&gt;Update to v2&lt;/h4&gt;

&lt;p&gt;The switch from SQLite to Postgres was pretty painful in Node.js. For Java and
Haskell the switch was easy and fast.&lt;/p&gt;

&lt;h4 id="deployment"&gt;Deployment&lt;/h4&gt;

&lt;p&gt;To deploy a Java webapp, you need a servlet container (I used
&lt;a href="http://www.eclipse.org/jetty/"&gt;Jetty&lt;/a&gt;) and deploy it within that. The
&lt;code&gt;war&lt;/code&gt; file usually includes all necessary dependencies.  Every Node.js app
starts its own server on its own port, so there isn’t much to it: install
Node.js, install the required libraries with &lt;code&gt;npm&lt;/code&gt;, Profit! Haskell produces a
single binary which can be copied to the destination. Starting the binary, also
starts the webserver and can thus be used directly or via a proxy.  There are
still some dynamic linked libraries which have to be present on the target
machine.&lt;/p&gt;

&lt;p&gt;The nice thing about Java is, that all necessary dependencies are bundled with
the app itself. Haskell and its type system also check whether newer versions
are still compatible, for Node.js it seems that our only option is to perform
adequate testing.&lt;/p&gt;

&lt;h4 id="summary"&gt;Summary&lt;/h4&gt;

&lt;p&gt;This sums up my endeavour: &lt;strong&gt;I’ve had the most fun writing the Go client,&lt;/strong&gt; but
the Haskell services has the fewest possibilities for error. Haskell is really,
really cool for writing REST services, and performs very good. Node.js is
very young and provides very good productivity and performance to get
&lt;em&gt;something&lt;/em&gt; up and running, but (to me), maintaining Node.js code seems like
something I wouldn’t want to do. Java is a compromise, nobody got every
fired for using Java (except, maybe someone on the Android team).&lt;/p&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:1"&gt;
      &lt;p&gt;What else to do with three similar REST services?&lt;a href="#fnref:1" rel="reference"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/y2qhWV30heY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/rest_frameworks.html</feedburner:origLink></entry>
 
 <entry>
   <title>Programming Languages in Joy and Sorrow</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/Ln-DW_c60I0/programming_languages_in_joy_and_sorrow.html" />
   <updated>2012-09-15T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/programming_languages_in_joy_and_sorrow</id>
   <content type="html">&lt;p&gt;Most of us (programmers) know, and need to know, many programming
languages. Some aren’t even perceived as programming languages any more
(Shell-Scripts), some make us a living (Java, C# etc.), some are hard to
replace (JavaScript), and some are just fun to play with (make your
choice).&lt;/p&gt;

&lt;p&gt;What makes programming languages differ is not syntax, syntax is nothing
more than a mechanical translation, much like a cipher: back and forth
without gaining or losing information.&lt;/p&gt;

&lt;p&gt;General purpose language don’t even differ in &lt;em&gt;what&lt;/em&gt; they’re able to
express. All of them are “Turing Complete”&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt; and hence are equally potent.&lt;/p&gt;

&lt;p&gt;What makes a difference is how programming in these languages feel like.
Even though Assembler and JavaScript are equally potent (in theory), they
are two very different beasts.&lt;/p&gt;

&lt;p&gt;What appeals to me are just a handful properties of a language:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;simplicity,&lt;/li&gt;
  &lt;li&gt;expressiveness,&lt;/li&gt;
  &lt;li&gt;performance,&lt;/li&gt;
  &lt;li&gt;productivity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="simplicity"&gt;Simplicity&lt;/h2&gt;

&lt;p&gt;If a programming language is complicated by itself, programs become
brittle, programmers are distracted, there is no uniform structure etc.
C++ is a wonderful and very expressive language, but it has so many ways
of doing things, so many features to learn (and distract) that I would not
care to use it again.&lt;/p&gt;

&lt;p&gt;Simplicity was one of C’s big appeals, the language is very lean and has a
small set of features. The language features were carefully chosen to be
general enough to not be too restrictive.&lt;/p&gt;

&lt;h2 id="expressiveness"&gt;Expressiveness&lt;/h2&gt;

&lt;p&gt;How much code do I need to write to get a job done? How good are the means
of abstraction (how often do I need to repeat myself)?&lt;/p&gt;

&lt;p&gt;Assembler doesn’t have much abstraction capabilities (mostly jumps),
whereas functional languages offer powerful ways of separating, combining,
and reusing code blocks.&lt;/p&gt;

&lt;p&gt;A simple &lt;em&gt;and&lt;/em&gt; expressive language is easy to understand, and has &lt;em&gt;few&lt;/em&gt;, but
powerful, means for abstraction.&lt;/p&gt;

&lt;h2 id="performance"&gt;Performance&lt;/h2&gt;

&lt;p&gt;Computers used to get faster every year for some time, currently we’ve
reached a plateau and instead of scaling up, we’re scaling out by adding
cores and machines.&lt;/p&gt;

&lt;p&gt;Our programs don’t get faster by waiting for a better machine anymore. We
need to actively take additional cores into consideration. The future (and
probably the present) is distributed!&lt;/p&gt;

&lt;p&gt;I think performance is still a major merit of today’s software. If your
service can’t scale to “internet scale”&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt;, you’ll lose. If your
competitor offers the same set of features, but twice as fast, you’ll
lose.&lt;/p&gt;

&lt;p&gt;So a modern programming does not need to be the fastest one on a single
machine and a single core, but it should be reasonable fast and scale
easily to threads and processes.&lt;/p&gt;

&lt;h2 id="productivity"&gt;Productivity&lt;/h2&gt;

&lt;p&gt;Computers have become insanely fast, but programmer productivity stayed
the same. Sure, we can’t call Intel for a brain-upgrade, but we can choose
and provide the right set of abstractions to support us.&lt;/p&gt;

&lt;p&gt;Besides the simplicity and expressiveness of a language, productivity
involves the available libraries, the community and the culture of the
community. Java, for example, has a very active Open Source culture, quite
untypical for a business related language.&lt;/p&gt;

&lt;p&gt;“Academic” (or, let’s call them “non-mainstream”) languages are often very
beautiful and expressive, but their lack of practical libraries makes it
hard to get up and running quickly. We’re in an age of quick-fixes and
easy gains – what’s the point of choosing the newest language du jour if
we can’t deliver faster (in the long run)?  What’s the point of
“engineering” if, in the end, we need even more time than by hacking&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" rel="footnote"&gt;3&lt;/a&gt;&lt;/sup&gt;?&lt;/p&gt;

&lt;p&gt;Productivity, for me, heavily affects the fun in programming and mostly
subsumes simplicity and expressiveness.&lt;/p&gt;

&lt;h1 id="language-assessment"&gt;Language assessment&lt;/h1&gt;

&lt;p&gt;In a business setting you rarely have a free choice of weapons, but for
personal or pet projects, you can do that. Most people I know stick to the
language from work because it is well known. Some are increasingly
unsatisfied with their day-job language and set out for the search of
their “own” language. I can’t tell you what the &lt;em&gt;best&lt;/em&gt; language is.
Everyone is different, like Yukihiro Matsumoto said
&lt;a href="http://www.artima.com/intv/ruby.html"&gt;here&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;No language can be perfect for everyone. I tried to make Ruby perfect
for me, but maybe it’s not perfect for you. The perfect language for
Guido van Rossum is probably Python.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You are different from everyone else. Embrace the difference. Use your
brain and make you own choice.&lt;/p&gt;

&lt;p&gt;Of course, given the &lt;a href="http://en.wikipedia.org/wiki/List_of_programming_languages"&gt;sheer amount of programming
languages&lt;/a&gt;,
making an educated guess is crucial. Taking only &lt;a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html"&gt;the 100 most popular
languages&lt;/a&gt;
into account is surely not too far off.&lt;/p&gt;

&lt;h2 id="go-philosophical"&gt;Go Philosophical&lt;/h2&gt;

&lt;p&gt;Languages are divided into a few categories concerning &lt;a href="http://en.wikipedia.org/wiki/Programming_paradigm"&gt;programming
paradigm&lt;/a&gt; (object
oriented, functional, procedural…), typing (strong, weak, static,
dynamic) etc.&lt;/p&gt;

&lt;p&gt;My personal preference is with statically typed functional languages
because they provide very good abstractions and safety through the
compiler.&lt;/p&gt;

&lt;h2 id="look-for-a-language-with-good-interop-functionality"&gt;Look for a language with good interop functionality.&lt;/h2&gt;

&lt;p&gt;We’ve invested a lot of time in building libraries, helpers, utilities
etc. Of course starting from scratch is fun, but it’s &lt;a href="http://www.joelonsoftware.com/articles/fog0000000069.html"&gt;rarely
economical&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you used to program in Java, start looking for JVM languages for
example.&lt;/p&gt;

&lt;h2 id="read-some-code-before-diving-in"&gt;Read some code before diving in&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://typing.io/lessons"&gt;Typing.io&lt;/a&gt; is a nice starting point for some
languages, and of course, there is always &lt;a href="https://github.com/languages"&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Do you feel comfortable with the layout, the language, does it feel
natural? Do you even understand some of it?&lt;/p&gt;

&lt;h2 id="enough-with-the-subjective-assessment-show-me-something-objective"&gt;Enough with the subjective assessment, show me something objective!&lt;/h2&gt;

&lt;p&gt;Here is an unbiased and objective survey of a few programming languages
I’m interested in. It’s totally foolproof and you certainly should start a
multimillion dollar company on it!&lt;/p&gt;

&lt;p&gt;This chart shows the ratio of the number of search results for&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;"c programming" "sucks"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;"c programming" "rocks"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;as returned by &lt;a href="http://search.yahoo.com"&gt;Yahoo!&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That is, &lt;code&gt;"c programming" "sucks"&lt;/code&gt; returns &lt;code&gt;20800&lt;/code&gt; results, &lt;code&gt;"c programming"
"rocks"&lt;/code&gt; returns &lt;code&gt;222000&lt;/code&gt; results, hence a ratio of &lt;code&gt;10.6731&lt;/code&gt; in the chart.
Thus, everything below &lt;code&gt;1&lt;/code&gt; means, there are more “sucks” results than
“rocks” results.&lt;/p&gt;

&lt;script type="text/javascript+protovis"&gt;
var drawchart = function(data, titles) {
  var w = 800,
      h = data.length * 25,
      x = pv.Scale.linear(0, Math.max.apply(Math, data) * 1.1).range(0, w),
      y = pv.Scale.ordinal(pv.range(data.length)).splitBanded(0, h, 4/5);

  /* The root panel. */
  var vis = new pv.Panel()
      .width(w)
      .height(h)
      .bottom(20)
      .left(70)
      .right(10)
      .top(5);

  /* The bars. */
  var bar = vis.add(pv.Bar)
      .data(data)
      .top(function() y(this.index))
      .height(y.range().band)
      .left(0)
      .width(x);

  /* The value label. */
  bar.anchor("right").add(pv.Label)
      .textStyle("white")
      .text(function(d) d.toFixed(1));

  /* The variable label. */
  bar.anchor("left").add(pv.Label)
      .textMargin(5)
      .textAlign("right")
      .text(function() titles[this.index]);

  /* X-axis ticks. */
  vis.add(pv.Rule)
      .data(x.ticks(5))
      .left(x)
      .strokeStyle(function(d) d ? "rgba(255,255,255,.3)" : "#000")
    .add(pv.Rule)
      .bottom(0)
      .height(5)
      .strokeStyle("#000")
    .anchor("bottom").add(pv.Label)
      .text(x.tickFormat);

  return vis;
};
&lt;/script&gt;

&lt;script type="text/javascript+protovis"&gt;
drawchart([
      10.6731,
      9.5855,
      78.7179,
      0.3916,
      2.3209,
      0.6548,
      0.8422,
      1.2212,
      74.6032,
      280.6667
    ], [
      "c",
      "java",
      "clojure",
      "go",
      "python",
      "ruby",
      "scheme",
      "javascript",
      "scala",
      "haskell"
    ]
).render();
&lt;/script&gt;

&lt;p&gt;Since &lt;a href="http://www.haskell.org"&gt;Haskell&lt;/a&gt;,
&lt;a href="http://www.clojure.org"&gt;Clojure&lt;/a&gt;, and &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt;
completely dominate the chart, here a version with the obvious winners
removed:&lt;/p&gt;

&lt;script type="text/javascript+protovis"&gt;
drawchart([
      10.6731,
      9.5855,
      0.3916,
      2.3209,
      0.6548,
      0.8422,
      1.2212,
    ], [
      "c",
      "java",
      "go",
      "python",
      "ruby",
      "scheme",
      "javascript",
    ]
).render();
&lt;/script&gt;

&lt;p&gt;The numbers were computed using &lt;a href="http://drive.google.com"&gt;Google Docs -
Spreadsheets&lt;/a&gt; and its awesome
&lt;a href="https://support.google.com/docs/bin/answer.py?hl=en&amp;amp;answer=155184"&gt;ImportXML&lt;/a&gt;
function:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;=ImportXML("http://search.yahoo.com/search?p="&amp;amp;C4,"//span[@id='resultCount']")
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cell &lt;code&gt;C4&lt;/code&gt;, referenced in the above code, contained the URL encoded
search-string, for example &lt;code&gt;%22c programming%22 %22rocks%22&lt;/code&gt;. Try it with
&lt;code&gt;prolog&lt;/code&gt; ;-).&lt;/p&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:1"&gt;
      &lt;p&gt;Even some configuration files are considered Turing Complete, like sendmail’s.&lt;a href="#fnref:1" rel="reference"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:2"&gt;
      &lt;p&gt;Whatever internet scale is in your domain.&lt;a href="#fnref:2" rel="reference"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:3"&gt;
      &lt;p&gt;You’ve got to measure the whole lifetime of a project, it doesn’t help to get something working very quickly but with huge amounts of bugs, hard to change etc. I guess that’s a topic for a whole book on its own.&lt;a href="#fnref:3" rel="reference"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/Ln-DW_c60I0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/programming_languages_in_joy_and_sorrow.html</feedburner:origLink></entry>
 
 <entry>
   <title>In the beginning was the Test...</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/xHBieSYED6s/in_the_beginning_was_the_test.html" />
   <updated>2011-10-08T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/in_the_beginning_was_the_test</id>
   <content type="html">&lt;p&gt;JUnit offers many features besides the standard &lt;code&gt;assertTrue&lt;/code&gt;/&lt;code&gt;assertEquals&lt;/code&gt; methods
most programmers use. Let’s browse through the newer and more exotic features.
They might come in handy at some time.&lt;/p&gt;

&lt;h1 id="junit-49-feature-roundup"&gt;JUnit 4.9 Feature Roundup&lt;/h1&gt;

&lt;p&gt;Assuming you know something about unit testing and JUnit in
particular, I won’t start at the very bottom, but talk a little about
the features introduces during the last few versions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Matchers&lt;/li&gt;
  &lt;li&gt;Assumptions&lt;/li&gt;
  &lt;li&gt;Categories&lt;/li&gt;
  &lt;li&gt;Theories&lt;/li&gt;
  &lt;li&gt;Rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope there is something new in here for you. &lt;a href="http://kentbeck.github.com/junit/javadoc/latest/"&gt;JUnits javadoc
documentation&lt;/a&gt; is very good,
but there is no single place describing these features.  It’s not my goal to
give a thorough treatment of them here, but it might be a good starting point.&lt;/p&gt;

&lt;h2 id="matchers"&gt;Matchers&lt;/h2&gt;
&lt;p&gt;By including &lt;a href="http://code.google.com/p/hamcrest/"&gt;Hamcrest&lt;/a&gt; (core)
into the default JUnit distribution, JUnit now allows the usage of
&lt;code&gt;assertThat&lt;/code&gt; leading to much easier to read tests and better error
messages:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testUsingAssertThat&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greaterThan&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt; &lt;span class="c1"&gt;// note, this will fail&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;JUnit includes only the Hamcrest core matchers, if you want/need more matchers, include
&lt;a href="http://code.google.com/p/hamcrest/"&gt;hamcrest-all 1.1&lt;/a&gt;. Included matchers are documented &lt;a href="http://kentbeck.github.com/junit/javadoc/4.9/org/hamcrest/CoreMatchers.html"&gt;here for
Hamcrest&lt;/a&gt;
and &lt;a href="http://kentbeck.github.com/junit/javadoc/4.9/org/junit/matchers/JUnitMatchers.html"&gt;here for JUnit
additions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;java.lang.AssertionError: 
Expected: is a value greater than &amp;lt;43&amp;gt;
     got: &amp;lt;42&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="assumptions"&gt;Assumptions&lt;/h2&gt;
&lt;p&gt;Assumptions allow tests to be ignored if the assumed condition isn’t met (instead of failling).&lt;/p&gt;

&lt;p&gt;This test will be ignored if it is run on a Windows OS (for example):&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testUsingAssumeThat&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;assumeThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;separator&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It is also possible to use assumptions in &lt;code&gt;@Before&lt;/code&gt; or &lt;code&gt;@BeforeClass&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;Output (for example):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Test 'org.interlinked.junit.assumption.BasicTest.testUsingAssumeThat' ignored
org.junit.internal.AssumptionViolatedException: got: "\", expected: is "/"
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="categories"&gt;Categories&lt;/h2&gt;
&lt;p&gt;Using categories it is possible to run only a subset of the tests. For example
slow tests, integration tests etc.&lt;/p&gt;

&lt;p&gt;Here, &lt;code&gt;TestCategoryA&lt;/code&gt; and &lt;code&gt;TestCategoryB&lt;/code&gt; are empty interfaces used to mark
the tests:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="nd"&gt;@Category&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCategoryA&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testCatA&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Category A test&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="nd"&gt;@Category&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCategoryB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testCatB&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Category B test&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="nd"&gt;@Category&lt;/span&gt;&lt;span class="o"&gt;({&lt;/span&gt; &lt;span class="n"&gt;TestCategoryA&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TestCategoryB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testCatAB&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Category A and B test&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using the &lt;code&gt;Categories&lt;/code&gt; suite, we can now execute only those tests that are in
“Category A”, but not in “Category B”:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@RunWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Categories&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Categories.IncludeCategory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCategoryA&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// this would run tests CatA and CatAB&lt;/span&gt;
&lt;span class="nd"&gt;@Categories.ExcludeCategory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCategoryB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// now test CatAB is excluded too&lt;/span&gt;
&lt;span class="nd"&gt;@Suite.SuiteClasses&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BasicTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CategoryASuite&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Category A test
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="theories"&gt;Theories&lt;/h2&gt;
&lt;p&gt;With theories we can write parameterized tests. We define a few theories and
some datapoints. JUnit will match the types of the datapoints and the theories.&lt;/p&gt;

&lt;p&gt;Again, we have to use a special suite class &lt;code&gt;Theories&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@RunWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Theories&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TheoryTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@DataPoint&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;POINT1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;POINT1&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nd"&gt;@DataPoint&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;POINT2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;POINT2&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// mind the plural!&lt;/span&gt;
  &lt;span class="c1"&gt;// uses only the items of the array, never the whole array!&lt;/span&gt;
  &lt;span class="nd"&gt;@DataPoints&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;POINTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;abc&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;cde&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;efg&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;ghi&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;};&lt;/span&gt;

  &lt;span class="nd"&gt;@DataPoint&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;POINTS_ARRAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;POINTS&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@Theory&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testTheory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Got: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Theory&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testTheoryWithTwoParams&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;param1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;param2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Got &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;param1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; and &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;param2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Theory&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// gets called with POINTS_ARRAY, nothing else&lt;/span&gt;
      &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Got called...&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;equalTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;POINTS_ARRAY&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Got POINT1 and POINT1
Got POINT1 and POINT2
Got POINT1 and abc
Got POINT1 and cde
Got POINT1 and efg
Got POINT1 and ghi
Got POINT2 and POINT1
Got POINT2 and POINT2
Got POINT2 and abc
Got POINT2 and cde
Got POINT2 and efg
Got POINT2 and ghi
Got abc and POINT1
Got abc and POINT2
Got abc and abc
Got abc and cde
Got abc and efg
Got abc and ghi
Got cde and POINT1
Got cde and POINT2
Got cde and abc
Got cde and cde
Got cde and efg
Got cde and ghi
Got efg and POINT1
Got efg and POINT2
Got efg and abc
Got efg and cde
Got efg and efg
Got efg and ghi
Got ghi and POINT1
Got ghi and POINT2
Got ghi and abc
Got ghi and cde
Got ghi and efg
Got ghi and ghi
Got called...
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="rules"&gt;Rules&lt;/h2&gt;
&lt;p&gt;Finally, rules allow us to add behaviour to tests. They can be thought of some
kind of AOP for JUnit. Using rules, we can often omit class hierarchies and
still reuse functionality using delegation.&lt;/p&gt;

&lt;p&gt;JUnit includes some rules to start with, but it is very easy to write our own rules.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RuleTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@Rule&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;TemporaryFolder&lt;/span&gt; &lt;span class="n"&gt;temporaryFolder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TemporaryFolder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="nd"&gt;@Rule&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;TestName&lt;/span&gt; &lt;span class="n"&gt;testName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TestName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;fileCreated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nd"&gt;@Rule&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;LoggingRule&lt;/span&gt; &lt;span class="n"&gt;loggingRuld&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;LoggingRule&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@Before&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;printTestName&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testName&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMethodName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Test&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testCreatingAFile&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="n"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="n"&gt;newFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temporaryFolder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test1&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isFile&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;fileCreated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Test&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt;  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testCheckIfItExists&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// depends on testCreatingAFile...&lt;/span&gt;
    &lt;span class="n"&gt;assumeTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileCreated&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// just to be sure ;)&lt;/span&gt;
    &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temporaryFolder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRoot&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAbsolutePath&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/test1&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// the file should not exist (unless we use ClassRule for the TemporaryFolder, for example)&lt;/span&gt;
    &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isFile&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NullPointerException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testThrowException&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NullPointerException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Starting: testCreatingAFile
testCreatingAFile
Finished: testCreatingAFile
Starting: testCheckIfItExists
testCheckIfItExists
Finished: testCheckIfItExists
Starting: testThrowException
testThrowException
Finished: testThrowException
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The
&lt;a href="http://kentbeck.github.com/junit/javadoc/4.9/org/junit/rules/TemporaryFolder.html"&gt;&lt;code&gt;TemporaryFolder&lt;/code&gt;&lt;/a&gt;
and
&lt;a href="http://kentbeck.github.com/junit/javadoc/4.9/org/junit/rules/TestName.html"&gt;&lt;code&gt;TestName&lt;/code&gt;&lt;/a&gt;
rules are included in JUnit, the LoggingRule is a simple example:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoggingRule&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;TestWatcher&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;starting&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Starting: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMethodName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;finished&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Finished: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMethodName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Other rules included (&lt;a href="http://kentbeck.github.com/junit/javadoc/4.9/org/junit/rules/TestRule.html"&gt;see JUnit’s javadoc&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;ErrorCollector&lt;/code&gt;: collect multiple errors in one test method&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;ExpectedException&lt;/code&gt;: make flexible assertions about thrown exceptions&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;ExternalResource&lt;/code&gt;: start and stop a server, for example&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;TemporaryFolder&lt;/code&gt;: create fresh files, and delete after test&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;TestName&lt;/code&gt;: remember the test name for use during the method&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;TestWatcher&lt;/code&gt;: add logic at events during method execution&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;Timeout&lt;/code&gt;: cause test to fail after a set time&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;Verifier&lt;/code&gt;: fail test if object state ends up incorrect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately, rules seem to be local to the defining class, so you
can’t put the into the suite class like @Before and @BeforeClass (which
is really nice for opening external resources once for all tests).&lt;/p&gt;

&lt;h2 id="misc-additions"&gt;Misc additions&lt;/h2&gt;

&lt;h3 id="infinitest"&gt;Infinitest&lt;/h3&gt;
&lt;p&gt;For each change you make, &lt;a href="http://infinitest.github.com/"&gt;Infinitest&lt;/a&gt;
runs all the dependent tests. It’s continous testing for Eclipse
and IDEA - free and open source (written by &lt;a href="http://improvingworks.com/"&gt;inproving
works&lt;/a&gt;)!&lt;/p&gt;

&lt;h3 id="classpathsuite"&gt;ClasspathSuite&lt;/h3&gt;
&lt;p&gt;Most IDEs have their own ways for finding test classes to run, but usually I
like to be IDE independent. Using the
&lt;a href="http://johanneslink.net/projects/cpsuite.jsp"&gt;ClasspathSuite&lt;/a&gt; it is possible
to have JUnit detect all test classes (or a subset of them) within the
classpath (written by Johannes Link). There are efforts to include it into
the standard distribution of JUnit.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/xHBieSYED6s" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/in_the_beginning_was_the_test.html</feedburner:origLink></entry>
 
 <entry>
   <title>Notebooks (dead wood)</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/DWxzPI2lbxE/leuchtturm1917.html" />
   <updated>2011-07-22T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/reviews/leuchtturm1917</id>
   <content type="html">&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/notebooks.jpg" alt="Notebooks" style="float:right; margin-left:10px" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://moleskine.com/"&gt;Moleskines&lt;/a&gt; were all the rage about six years ago.
Whole &lt;a href="http://www.google.com/search?q=moleskine+blog"&gt;blogs&lt;/a&gt; were, and still
are, dedicated to them. Today, still many people carry these little black
books.&lt;/p&gt;

&lt;p&gt;I too loved these little books, but in the last few years I’ve changed some
parameter of my journal every time I needed a new one. I changed the brand, the
size, I used soft and hard covers, plain, square or ruled (although, they were
always black).&lt;/p&gt;

&lt;p&gt;It was a fun experiment, but now I’ve come to a conclusion of what suits my
needs best: &lt;a href="http://www.leuchtturm1917.com"&gt;Leuchtturm 1917&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.leuchtturm1917.com/content/notizbuch-master"&gt;Master&lt;/a&gt; (A4+) and&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.leuchtturm1917.com/content/notizbuch-medium"&gt;Medium&lt;/a&gt; (A5)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;either dotted or plain.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Master&lt;/em&gt; is large enough for keeping full A4 pages. I use it for
plannings, sketches, technical stuff etc. Most of the time it sits on my
desk and waits to be filled - usually one to two pages per day.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Medium&lt;/em&gt; is just the right size for a journal. It fits easily in almost
every bag, is large enough for notes, quotes, thoughts and so on. The
smallest format, A6, is also quite nice. But for me, the &lt;em&gt;Medium&lt;/em&gt; is simply the
best choice.&lt;/p&gt;

&lt;p&gt;The following sounds like an advertisement, but the tagline of the
Leuchtturm 1917 company is “Details machen den Unterschied” (“Details make
all the difference”), I &lt;em&gt;have&lt;/em&gt; to include some of their noteworthy details:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Ink proof paper - earlier editions of the notebooks used a thinner paper
(much like the paper used in Moleskine notebooks), but recent editions use a
80g/qm paper - perfectly suited for a fountain pen.&lt;/li&gt;
  &lt;li&gt;The “Dotted” variant is a nice compromise between plain and square, it’s
unobtrusive and still provides enough guidance.&lt;/li&gt;
  &lt;li&gt;Numbers and Index - the pages are numbered and a small index is printed on
the first few pages.&lt;/li&gt;
  &lt;li&gt;Detachable sheets - some companies offer notebooks with detachable sheets,
sometimes you can rip out half of the notebook. Leuchtturm only has 8
sheets which is more than I ever ripped out of a notebook, so I consider
this a plus.&lt;/li&gt;
  &lt;li&gt;Labelling stickers - quite nice for organisation-fanatics, during usage we
have the slick plain look of the black notebook we all love, but for
archiving purposes there are a few labelling stickers in each notebook
package.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though we’ve access to email, note-taking applications, the Web etc.
almost all the time, I still love the old classy feeling of a notebook and (in
my case) a fountain pen.&lt;/p&gt;

&lt;p&gt;I’ll end this post with a few links for your
&lt;a href="http://freelanceswitch.com/productivity/the-monster-collection-of-moleskine-tips-tricks-and-hacks/"&gt;reading&lt;/a&gt;/&lt;a href="http://www.instructables.com/id/Save-$200-in-2-minutes-and-have-the-worlds-best-wr/"&gt;tinkering&lt;/a&gt;
pleasure.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/DWxzPI2lbxE" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/reviews/leuchtturm1917.html</feedburner:origLink></entry>
 
 <entry>
   <title>How to Hide Google's "Google Plus Notification Count"</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/a4hpKrLPAzI/disable_google_plus_notification.html" />
   <updated>2011-07-19T10:00:00+02:00</updated>
   <id>http://blog.interlinked.org/misc/disable_google_plus_notification</id>
   <content type="html">&lt;p&gt;To hide the Google Plus notifications on the upper right of Google’s
services, install Adblock (&lt;a href="http://adblockplus.org/en/"&gt;Adblock Plus for Firefox&lt;/a&gt; or &lt;a href="http://www.chromeadblock.com"&gt;Adblock for
Chrome&lt;/a&gt;) and add this rule to your ruleset:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;##A#gbg1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The notification count is a link (A) with id &lt;code&gt;gbg1&lt;/code&gt;, this rule hides that
element. Let me know if it works for you, or not.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/a4hpKrLPAzI" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/misc/disable_google_plus_notification.html</feedburner:origLink></entry>
 
 <entry>
   <title>JavaScript</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/_lDujQTiY68/javascript.html" />
   <updated>2011-07-19T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/javascript</id>
   <content type="html">&lt;p&gt;JavaScript was developed 16 years ago by Brendan Eich. The majority of
our Web experience relies heavily on JavaScript. Without it, we’d still
have to reload a page for every click, we wouldn’t have the ability to
interact in a sane way with the Web, and - I speculate - the Web
wouldn’t be as omnipresent as it is now. Usability matters.&lt;/p&gt;

&lt;p&gt;JavaScript is also one of the worst languages I’ve ever seen. It has
many sharp edges and rough parts. Anyways, it also has very unusual, and
hence, interesting parts like prototypical inheritance and functional
aspects.&lt;/p&gt;

&lt;p&gt;Even though, JavaScript is a standardized language, ECMAScript, there are still
some undefined parts. The version that almost all Browsers support,
ECMAScript3, was a turning point for the modern Web, ECMAScript4 was too bold
and didn’t happen. And now ECMAScript5 is coming.  ECMAScript5 still has some
of the weird parts, but made a few clear cuts. Now the remaining
inconsistencies between newer JavaScript implementations in browser shouldn’t
be that bad. Of course, this doesn’t help much since there is always an IE6
around the corner.&lt;/p&gt;

&lt;p&gt;The domain of JavaScript is the browser, I suppose that more than 99% of
the worlds JavaScript code runs within a browser. But it is not limited
to the browser. There are JavaScript implementations that can be
embedded in other applications (e.g.
&lt;a href="http://www.mozilla.org/rhino/"&gt;Rhino&lt;/a&gt; to embed it into Java), or the
awesome &lt;a href="http://nodejs.org/"&gt;NodeJS&lt;/a&gt; project which allows JavaScript to
be used as a general purpose language (with focus on network
applications).&lt;/p&gt;

&lt;p&gt;JavaScript seems to invade our lives wherever it can. Mac OS X Dashboard
widgets, browser plugins, Smartphone apps, Webservers etc. there is
always a way to use JavaScript!&lt;/p&gt;

&lt;p&gt;With the advent of HTML5, there are even more possibilities like opening
&lt;a href="http://en.wikipedia.org/wiki/WebSockets"&gt;WebSockets&lt;/a&gt; etc.&lt;/p&gt;

&lt;p&gt;Few languages are so clearly worth learning as JavaScript.
 - It’s an interesting language that doesn’t restrict how you use it.
 - It’s a language you get paid for developing in.
 - It’s still cool (who cares about Java anymore?).
 - It’s here to stay (for some time, though).&lt;/p&gt;

&lt;p&gt;So, to sum it up, I believe investing in JavaScript pays off. Even if
you’re an “enterprise developer” or something. JavaScript will get
you, sooner or later, so get it first!&lt;/p&gt;

&lt;p&gt;As Douglas Crockford said, JavaScript is a misunderstood language
because few people take time to learn it properly. Take your time and
get familiar with it. Two resources I’d recommend are:
 - Douglas Crockford - JavaScript the Good Parts (pre ECMAScript5)
 - David Flanagan - JavaScript - The Definitive Guide (covers ECMAScript5)&lt;/p&gt;

&lt;p&gt;Don’t get too fixed on ECMAScript5, it can be easily “emulated” with
ECMAScript3, and few browser fully support it by now.&lt;/p&gt;

&lt;p&gt;Some cool stuff in, with or about JavaScript:
 - &lt;a href="http://bellard.org/jslinux/"&gt;Booting the Linux Kernel in JavaScript - right in your Browser&lt;/a&gt;
 - &lt;a href="http://jashkenas.github.com/coffee-script/"&gt;CoffeeScript a scripting language that compiles to JavaScript&lt;/a&gt;
 - &lt;a href="http://mbostock.github.com/protovis/"&gt;Protovis - one of many visualization libraries&lt;/a&gt;
 - &lt;a href="http://www.jslint.com/"&gt;JSLint - to prevent pitfalls&lt;/a&gt;
 - &lt;a href="http://www.codinghorror.com/blog/2007/05/javascript-the-lingua-franca-of-the-web.html"&gt;JavaScript - the lingua franca of the Web&lt;/a&gt;
 - &lt;a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm"&gt;ECMAScript 5.1 Specification&lt;/a&gt;
 - &lt;a href="http://addyosmani.com/blog/essentialjsdesignpatternsupdate1/"&gt;JavaScript Design Patterns&lt;/a&gt;
 - &lt;a href="http://point-at-infinity.org/jsaes/"&gt;AES in JavaScript&lt;/a&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/_lDujQTiY68" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/javascript.html</feedburner:origLink></entry>
 
 <entry>
   <title>How to dive into Legacy Code</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/F_csQZyJeQ8/how_to_dive_into_legacy_code.html" />
   <updated>2011-07-18T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/how_to_dive_into_legacy_code</id>
   <content type="html">&lt;p&gt;Diving into legacy code written some time ago can be a daunting task. It
doesn’t even matter much if we’ve been writing it ourselves, or somebody else,
code rots faster than we’d like to admit.&lt;/p&gt;

&lt;p&gt;Currently faced with such a task I tried to do it in a systematic and
repeatable manner.&lt;/p&gt;

&lt;h2 id="my-steps"&gt;My steps&lt;/h2&gt;

&lt;p&gt;First try to find the modules and their dependencies. I used &lt;a href="http://www.jetbrains.com/idea/features/dependency_analysis.html"&gt;IntelliJ
IDEA&lt;/a&gt; for my
current Java project. Since it also uses Maven, finding the dependencies was
easy.&lt;/p&gt;

&lt;p&gt;Create a graph of module interdependencies. Which modules depend on which? Find
the “edges” of the system (modules that do not depend on other modules). I
found them to be the best starting point for a more detailed analysis.&lt;/p&gt;

&lt;p&gt;Find out what the purpose of each module is. Is it a layer in the system (like
a DAO-module)? Is it a cross-cutting concern (model classes)?&lt;/p&gt;

&lt;p&gt;The next step is to analyse each module by itself. For this step I recommend
using &lt;a href="http://www.stack.nl/~dimitri/doxygen/"&gt;doxygen&lt;/a&gt;. It can generate a very
good documentation of the software at hand, even if no doxygen (or any other
type of markup) was used, by analysing the dependencies, class hierarchies,
call graphs of the program. doxygen supports many languages, chances are high
yours will be too.&lt;/p&gt;

&lt;p&gt;To get the most out of doxygen, I’ve used the following configuration
file which enables many of the advanced analysis features (like call
graphs etc): &lt;a href="/static/files/doxygen.config"&gt;doxygen.config&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You have to edit the file and provide - at least - the input and
output directories! After that, it’s simply a &lt;code&gt;doxygen
doxygen.config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To generate this kind of documentation easily from Maven, here is a
similar doxygen-maven-plugin configuration:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="xml"&gt;    &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.soebes.maven.plugins.dmg&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;doxygen-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;projectName&amp;gt;&lt;/span&gt;${project.artifactId}&lt;span class="nt"&gt;&amp;lt;/projectName&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;projectNumber&amp;gt;&lt;/span&gt;${project.version}&lt;span class="nt"&gt;&amp;lt;/projectNumber&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;optimizeOutputJava&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/optimizeOutputJava&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;extractAll&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/extractAll&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;extractStatic&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/extractStatic&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;recursive&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/recursive&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;exclude&amp;gt;&lt;/span&gt;.git&lt;span class="nt"&gt;&amp;lt;/exclude&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;excludePatterns&amp;gt;&lt;/span&gt;*/test/*&lt;span class="nt"&gt;&amp;lt;/excludePatterns&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;inlineSources&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/inlineSources&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;referencedByRelation&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/referencedByRelation&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;referencesRelation&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/referencesRelation&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;hideUndocRelations&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/hideUndocRelations&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;umlLook&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/umlLook&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;callGraph&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/callGraph&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;callerGraph&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/callerGraph&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;generateLatex&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/generateLatex&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;generateLatex&lt;/code&gt; option is nice if you wish to produce PDF files (for
viewing on a Kindle for example).&lt;/p&gt;

&lt;p&gt;With this plugin configured in you pom.xml, &lt;code&gt;mvn doxygen:report&lt;/code&gt; is
your workhorse.&lt;/p&gt;

&lt;p&gt;If you’re unsure if the generated documentation is worth it, take a look at the
&lt;a href="/static/files/junit-4.8.2-doxygen.zip"&gt;doxygen documentation of JUnit
4.8.2 (zip file, 7.6MB)&lt;/a&gt;.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/F_csQZyJeQ8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/how_to_dive_into_legacy_code.html</feedburner:origLink></entry>
 
 <entry>
   <title>Haskell Books and Tutorials</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/GEr_k22FqNg/haskell_tutorials_and_books.html" />
   <updated>2008-10-24T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/haskell_tutorials_and_books</id>
   <content type="html">&lt;p&gt;Haskell is really a language very worth knowing. It does many things so different than most other languages which I really enjoy.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d like to use this post to mention a few really good resources for learning Haskell:&lt;/p&gt;
&lt;h2&gt;Learn you a Haskell&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://learnyouahaskell.com/"&gt;Learn you a Haskell&lt;/a&gt; is a very fun and entertaining tutorial for Haskell very much in the spirit of &lt;a href="http://poignantguide.net/ruby/"&gt;Why&amp;#8217;s poignant guide to Ruby&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It isn&amp;#8217;t finished yet, but it&amp;#8217;s really good to start with. (Via &lt;a href="http://wadler.blogspot.com/"&gt;Wadler&amp;#8217;s Blog&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;Real World Haskell&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://book.realworldhaskell.org/read/"&gt;Real World Haskell&lt;/a&gt; is a upcoming book I really look forward to. It is freely available on its website, so check it out.&lt;/p&gt;
&lt;h2&gt;Wikibook&lt;/h2&gt;
&lt;p&gt;There is also a good collection of Haskell topics on &lt;a href="http://en.wikibooks.org/wiki/Programming:Haskell"&gt;Wikibooks &amp;#8211; Programming/Haskell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wikibook is more interesting if you already know a bit of Haskell and would like to understand it more in depth.&lt;/p&gt;
&lt;h2&gt;Others&lt;/h2&gt;
&lt;p&gt;I liked &lt;a href="http://hal3.name/docs/daume02yaht.ps"&gt;Yet another Haskell Tutorial&lt;/a&gt; very much, this aims at people with a bit of background, though.&lt;/p&gt;
&lt;p&gt;Another more recent book on Haskell is &lt;a href="http://www.cs.nott.ac.uk/~gmh/book.html"&gt;Programming in Haskell&lt;/a&gt; which is nice, but also quite basic &lt;span class="caps"&gt;IMO&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Of course there is always the &lt;a href="http://www.haskell.org/tutorial/"&gt;Gentle introduction to Haskell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Enjoy.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/GEr_k22FqNg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/haskell_tutorials_and_books.html</feedburner:origLink></entry>
 
 <entry>
   <title>Git Overview</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/LADr1GBkwoA/git.html" />
   <updated>2008-08-24T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/tutorials/git</id>
   <content type="html">&lt;p style="float:left;"&gt;&lt;img src="http://blog.interlinked.org/static/images/git/git-logo.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;My version control journey started with &lt;span class="caps"&gt;CVS&lt;/span&gt;, after that I looked at &lt;span class="caps"&gt;SVN&lt;/span&gt;, but never really used it.  The shortcomings of centralized repositories were too obvious and with my increasing interest in Haskell I jumped on the distributed version control train with &lt;a href="http://blog.interlinked.org/tutorials/darcs.html"&gt;Darcs&lt;/a&gt;.  I really, really liked it, but it had some nasty things too. After a while I was looking for something different and stumbled over &lt;a href="http://blog.interlinked.org/reviews/mercurial.html"&gt;Mercurial&lt;/a&gt;, again I was really happy with it but somehow my journey wasn&amp;#8217;t over yet.&lt;/p&gt;
&lt;p&gt;Recently I was watching two &lt;a href="http://www.git.or.cz"&gt;Git&lt;/a&gt; techtalks on YouTube:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.youtube.com/watch?v=4XpnKHJAok8"&gt;Linus Torvalds on Git&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.youtube.com/watch?v=8dhZ9BXQgc4"&gt;Randal Schwartz on Git&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The two talks are very different. The first one is more about why there&amp;#8217;s place for yet another source code management with the rare opportunity to see Linus Torvalds giving a talk. The second one is about Git&amp;#8217;s technicalities (commands etc.).&lt;/p&gt;
&lt;h2&gt;Basic Terms&lt;/h2&gt;
&lt;p&gt;Git distinguishes between the workspace, the index/staging area, the object store and remote repositories.&lt;/p&gt;
&lt;p&gt;The workspace is where you do your actual work. It contains tracked files, untracked files and a special directory &amp;#8220;.git&amp;#8221;.&lt;/p&gt;
&lt;p&gt;The index (or staging area) is used for preparing commits. You can add files to the next commit or even only &lt;strong&gt;parts&lt;/strong&gt; of files for the next commit. All the changes you&amp;#8217;d like to commit get into the index first.  A commit takes everything in the index and persists it in the object store.&lt;/p&gt;
&lt;p&gt;The object store isn&amp;#8217;t really an issue here, and remote repositories are more or less clear what they are.&lt;/p&gt;
&lt;h2&gt;Quick Intro&lt;/h2&gt;
&lt;p style="float:right;"&gt;&lt;img src="http://blog.interlinked.org/static/images/git/high-level-commands.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;For a more complete introduction see the &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html"&gt;Git tutorial&lt;/a&gt; (the cool stuff is in the next section).&lt;/p&gt;
&lt;p&gt;Somewhere on the &lt;span class="caps"&gt;KDE&lt;/span&gt; Project I found &lt;a href="http://ktown.kde.org/~zrusin/git/"&gt;a really nice Cheat-Sheet&lt;/a&gt; for Git.&lt;/p&gt;
&lt;p&gt;To create a new repository just issue&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;git init&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To start tracking files (or content) issue&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;git add &amp;lt;files&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To commit the added changes (note, only the state of the files &lt;strong&gt;when you issued&lt;br /&gt;
&lt;code&gt;add&lt;/code&gt;&lt;/strong&gt; will be recorded) issue&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;git commit&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To push changes to a remote repository (ssh, filesystem etc.) issue&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;git push &amp;lt;remote url&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To clone a complete repository onto your local disk issue&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;git clone &amp;lt;remote url&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I like to do some general configuration for all my projects, something like this:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
git config --global user.name "Your Name"
git config --global user.email your.mail@host.com
git config --global color.ui auto
git config --global color.interactive auto
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;This tells Git who you are and enables some nice color-features of Git.&lt;/p&gt;
&lt;p&gt;To get the most out of Git learn one of these commands:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;git help &amp;lt;command&amp;gt;&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;man git-&amp;lt;command&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, &lt;code&gt;git help config&lt;/code&gt; is equivalent to &lt;code&gt;man git-config&lt;/code&gt;, similarily, &lt;code&gt;git config...&lt;/code&gt; is equivalent to &lt;code&gt;git-config...&lt;/code&gt;. The latter seems to be discouraged (since Git switches to a library approach or something), but is often used in tutorials or manuals.&lt;/p&gt;
&lt;p&gt;That may be the most used commands with Git, the more interesting ones &amp;#8211; and the ones for which you may want to switch to Git follow:&lt;/p&gt;
&lt;h2&gt;Commands&lt;/h2&gt;
&lt;h3&gt;Adding/Removing changes to/from the Index&lt;/h3&gt;
&lt;p&gt;To add all changes in a file, simply use &lt;code&gt;add&lt;/code&gt;, some examples:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;add .&lt;/code&gt; adds all files in the current directory and its sub-directories to the index&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;add &amp;lt;file&amp;gt;&lt;/code&gt; adds a specific file to the index&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;add -u&lt;/code&gt; adds all changed files to the index (that is, it adds alls files Git knows about and that have changed)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;add --patch&lt;/code&gt; lets you decide whether you want to include smaller changes within a file instead of all changes in the file(s) see &lt;a href="http://tomayko.com/writings/the-thing-about-git"&gt;The Thing About Git&lt;/a&gt; for a larger example. This is extremely useful if you accidentally made two unrelated changes to a file and you want to keep your commits clean (you &lt;strong&gt;do&lt;/strong&gt; want to keep your commits clean, don&amp;#8217;t you?!)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;add -i&lt;/code&gt; is an interactive version of &lt;code&gt;add&lt;/code&gt; with a text-based &lt;span class="caps"&gt;GUI&lt;/span&gt; combining all the above capabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you accidentally added some changes to the index, simply use &lt;code&gt;reset&lt;/code&gt; to clean it, or specify the file to remove from the index, like &lt;code&gt;reset &amp;lt;file&amp;gt;&lt;/code&gt;.  &lt;code&gt;reset&lt;/code&gt; can do more than simply cleaning the index, you can use it to restore the state of the latest commit by using &lt;code&gt;reset --hard&lt;/code&gt;. &lt;code&gt;reset&lt;/code&gt; also takes a parameter telling it which commit to consider &amp;#8211; instead of using the latest &lt;code&gt;HEAD&lt;/code&gt;, use &lt;code&gt;HEAD^&lt;/code&gt; for the parent of the actual &lt;code&gt;HEAD&lt;/code&gt;, or give it a SHA1 hash&amp;#8230; . Take a look &lt;a href="http://andy.delcambre.com/2008/3/12/git-reset-in-depth"&gt;at this post&lt;/a&gt; for a better treatment of &lt;code&gt;git reset&lt;/code&gt; and its possibilities.&lt;/p&gt;
&lt;h3&gt;Checking differences between commits/index/working directory&lt;/h3&gt;
&lt;p&gt;Sometimes you need to know what exactly the differences between two commits or the working directory and the index (or some commit) is.&lt;/p&gt;
&lt;p&gt;This is actually fairly trivial with any revision control system, and of course also with git.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;diff&lt;/code&gt; compares your working directory with the index&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;diff --cached&lt;/code&gt; compares your index with the latest commit (or any named commit you supply)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;diff &amp;lt;commit&amp;gt;&lt;/code&gt; compares your working directory with the named commit (use &lt;code&gt;HEAD&lt;/code&gt; for the latest commit)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;diff &amp;lt;commit&amp;gt; &amp;lt;commit&amp;gt;&lt;/code&gt; compares (surprise) two named commits (for example, &lt;code&gt;diff HEAD HEAD^&lt;/code&gt; shows the differences from the last two commits)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/git/diff.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;To get a high-level view of changed files, Git offers the &lt;code&gt;status&lt;/code&gt; command.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;status&lt;/code&gt; shows a summary of changed files, files added to the index and files not tracked.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;status -a&lt;/code&gt; shows what the index &lt;strong&gt;would&lt;/strong&gt; look like if you issued &lt;code&gt;add -u&lt;/code&gt; or a &lt;code&gt;commit -a&lt;/code&gt; (that is, all changed files get commited or added to the index).&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;status -u {no, normal, all}&lt;/code&gt; using the &lt;code&gt;-u&lt;/code&gt; parameter, Git&amp;#8217;s behavior concerning untracked files can be changed (don&amp;#8217;t show untracked files, show only files and directories, or show all untracked files recursively).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another way to get an overview of your controlled content is by using &lt;code&gt;ls-files&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;ls-files&lt;/code&gt; shows all tracked files&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;ls-files -t&lt;/code&gt; shows files with some additional information (like cached, modified etc.)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;ls-files --others&lt;/code&gt; shows untracked files&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Somehow I find this more interesting than the &lt;code&gt;status&lt;/code&gt; output, but this may come from my Mercurial experiences where &lt;code&gt;hg status&lt;/code&gt; would output a very similar list as &lt;code&gt;ls-files -t&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Most projects have some files which should not be tracked, for example binaries built from source, or backup-files from your editor&amp;#8230; . Using &lt;code&gt;.gitignore&lt;/code&gt; you can tell Git to always ignore these files (unless you order it to show you also ignored files, though).&lt;/p&gt;
&lt;p&gt;There are several ways to tell Git what to ignore. The most common one is by creating a &lt;code&gt;.gitignore&lt;/code&gt; file in the root of your project. This file could be added to the index and would be shared. The nice thing with this file is, that you can keep one in each sub-directory overriding the configuration of the parent directory. See &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/gitignore.html"&gt;gitignore&lt;/a&gt; for more.&lt;/p&gt;
&lt;p&gt;The second way, local to your repository, is to edit the file &lt;code&gt;.git/info/exclude&lt;/code&gt; to your needs. On Mac OS X, Git automatically adds &lt;code&gt;.DS_Store&lt;/code&gt; files to that exclude file.&lt;/p&gt;
&lt;p&gt;The third way is to specify a &lt;code&gt;core.excludesfile&lt;/code&gt; configuration (for example &lt;code&gt;git config --global core.excludesfile "/absolute/path/.gitglobalexclude"&lt;/code&gt;) and create a global ignore file (I think an absolute path is needed, but a &lt;a href="http://n2.nabble.com/-PATCH--Support-%22core.excludesfile-%3D-~-.gitignore%22-td742043.html"&gt;patch enabling relative paths&lt;/a&gt; was submitted).&lt;/p&gt;
&lt;p&gt;The format of the files is simple:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;!file&lt;/code&gt; &lt;strong&gt;never&lt;/strong&gt; ignore this file (use &lt;code&gt;!asdf.o&lt;/code&gt; if you excluded &lt;code&gt;*.o&lt;/code&gt;, but you want to track &lt;code&gt;asdf.o&lt;/code&gt;)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;/file&lt;/code&gt; ignore the file in the root of the &lt;strong&gt;project&lt;/strong&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;file&lt;/code&gt; ignore the file anywhere in the project&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;*.o&lt;/code&gt; ignore all files with an &amp;#8220;.o&amp;#8221; ending&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;dir/&lt;/code&gt; ignore the directory &amp;#8220;dir&amp;#8221; but not the file &amp;#8220;dir&amp;#8221;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Commiting changes&lt;/h3&gt;
&lt;p&gt;So, let&amp;#8217;s say we have a clean collection of changes in the index. The next step is to commit it.&lt;/p&gt;
&lt;p&gt;The basic command is simple, just &lt;code&gt;commit&lt;/code&gt;, but you can do more.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;commit -a&lt;/code&gt; commit all changed files (adding every changed file to the index)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;commit -m "commit message"&lt;/code&gt; supply the commit message at the command line&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;commit --amend&lt;/code&gt; edit the previous commit (that is, the new commit merges with the old one)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With Git it&amp;#8217;s common to make branches for bigger experiments. Use a branch for example if you want to implement a new feature which requires many changes in your code-base, but it takes too long for a single commit.&lt;/p&gt;
&lt;p&gt;So, to make a branch from the current &lt;span class="caps"&gt;HEAD&lt;/span&gt;, just issue &lt;code&gt;checkout -b name&lt;/code&gt;. This creates a branch named &amp;#8220;name&amp;#8221; and switches to it. This is equivalent to &lt;code&gt;branch name&lt;/code&gt; &lt;code&gt;checkout name&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In this branch you can do whatever is needed to implement the new feature, but if necessary, you can switch back to the old branch (for maintenance or something). After you&amp;#8217;ve completed your changes, just merge the branch with the new feature back to the original branch &lt;code&gt;merge name&lt;/code&gt;.  After that you can safely delete the &amp;#8220;name&amp;#8221; branch &lt;code&gt;branch -d name&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The following picture shows two branches, Branch B is created during the working directory (red line) points to Branch A, we can switch between the branches with &lt;code&gt;checkout&lt;/code&gt; and finally delete Branch B.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/git/branching.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Of course there can be conflicts while merging the changes from the other branch into a branch which has evolved by itself. Either you resolve the conflicts all at once, or you keep your branch with the new feature more or less up to date with &lt;code&gt;rebase&lt;/code&gt;. After each change to the master branch, you could issue a &lt;code&gt;rebase master&lt;/code&gt; in the new branch to get the new changes of the master branch incorporated into your &amp;#8220;name&amp;#8221; branch.&lt;/p&gt;
&lt;p&gt;Another very nice feature of &lt;code&gt;rebase&lt;/code&gt; is to merge many commits into a single commit (or edit some of them). Suppose you made your changes within a new branch, now you&amp;#8217;re ready but you&amp;#8217;d like to have a single commit containing all changes of the branch. Just issue &lt;code&gt;rebase -i master&lt;/code&gt;, and Git with alls commits leading from master to the current &lt;span class="caps"&gt;HEAD&lt;/span&gt;. Replace each &amp;#8220;pick&amp;#8221; with &amp;#8220;squash&amp;#8221; and Git merges all the commits into a single new one (you get to supply a new commit message). Look at &lt;a href="http://blog.madism.org/index.php/2007/09/09/138-git-awsome-ness-git-rebase-interactive"&gt;git awsome-ness&lt;/a&gt; for a complete example.&lt;/p&gt;
&lt;p&gt;The following diagram shows how commits are connected when a branch is made.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/git/branch.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;From the branch we can do a merge (first picture) or a rebase (second picture). Note that the &lt;code&gt;merge&lt;/code&gt; automatically issues a commit if no conflicts arise!&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/git/merge.png" alt="" /&gt; &lt;img src="http://blog.interlinked.org/static/images/git/rebase.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Here a small illustration what you &lt;strong&gt;could&lt;/strong&gt; do with a &lt;code&gt;rebase&lt;/code&gt; command:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/git/rebase-i.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;For smaller changes there&amp;#8217;s also a special holding area for changes. Suppose you&amp;#8217;re in the middle of a bigger change and you &lt;strong&gt;have&lt;/strong&gt; to quickly fix something completely unrelated. Just issue &lt;code&gt;stash&lt;/code&gt; and Git will put away all your current uncommited changes and present you with a clean working directory.  Now make the quick-fix, commit and issue &lt;code&gt;stash pop&lt;/code&gt; (equivalent to &lt;code&gt;stash apply&lt;/code&gt; and &lt;code&gt;stash drop&lt;/code&gt;) to continue working on your fancy new feature.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s also possible to stack stashes up, use &lt;code&gt;stash list&lt;/code&gt; to see a list of stashes. If you come to the conclusion that your stashed changes deserve their own branch, issue &lt;code&gt;stash branch foo&lt;/code&gt; to create a new branch &amp;#8220;foo&amp;#8221; and pop the latest stashed changes.&lt;/p&gt;
&lt;p&gt;You &lt;strong&gt;never&lt;/strong&gt; should temper with commits you already published to a remote repository (or other people)! If you find a mistake in a published commit use &lt;code&gt;revert &amp;lt;commit&amp;gt;&lt;/code&gt; which records a special commit telling other people that something isn&amp;#8217;t right with the specified commit.&lt;/p&gt;
&lt;h3&gt;Sharing or &amp;#8220;backing up&amp;#8221; your work&lt;/h3&gt;
&lt;p&gt;Sometimes you&amp;#8217;re not the one who started the project, or you simply reinstalled or changed the computer. How do you get your repository back?&lt;/p&gt;
&lt;p&gt;Nothing simpler than that: &lt;code&gt;clone &amp;lt;url&amp;gt;&lt;/code&gt;. Unfortunately, clone cannot clone &lt;strong&gt;to&lt;/strong&gt; a remote repository. I can&amp;#8217;t clone my local project to my backup server &amp;#8211; I have to either scp it to it or create a project there and pull the changes.  After that I can use the standard command to publish or receive changes.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;clone&lt;/code&gt; sets up all necessary configurations and you can simply issue &lt;code&gt;pull&lt;/code&gt; to update your repository with remote changes or &lt;code&gt;push&lt;/code&gt; to send your changes to the remote repository.&lt;/p&gt;
&lt;p&gt;In a distributed environment it&amp;#8217;s not uncommon that you might want to push or pull from different remote repositories.  For that reason, Git allows you to configure shortcuts to other repositories. The main remote repository is called &amp;#8220;origin&amp;#8221;, and you usually push or pull the master branch. &lt;code&gt;pull&lt;/code&gt; is a twofold operation, it first fetches the contents (using &lt;code&gt;fetch&lt;/code&gt;) and then merges the new contents with your changes. Of course you could also use &lt;code&gt;fetch&lt;/code&gt;, inspect the changes and &lt;code&gt;merge&lt;/code&gt; afterwards.&lt;/p&gt;
&lt;p&gt;So, how to you want clone the Git repository:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git clone git://git.kernel.org/pub/scm/git/git.git&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;After the clone, we can look at the remote sites and their respective URLs with &lt;code&gt;remote -v&lt;/code&gt;. To look which branches are available at the remote site, issue &lt;code&gt;branch -r&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
me@host:git % git remote -v 
origin	git://git.kernel.org/pub/scm/git/git.git
me@host:git % git branch -r
  origin/HEAD
  origin/html
  origin/maint
  origin/man
  origin/master
  origin/next
  origin/pu
  origin/todo
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Now let&amp;#8217;s add another repository containing the Git project (note the git2 subdomain):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git remote add mirror git://git2.kernel.org/pub/scm/git/git.git&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This tells Git to add the given &lt;span class="caps"&gt;URL&lt;/span&gt; with the shorthand &amp;#8220;mirror&amp;#8221; and to track all branches. If you&amp;#8217;d like to track only some branches, for example only the master branch add &lt;code&gt;-t master&lt;/code&gt; to the command.&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
me@host:git % git remote -v 
mirror	git://git2.kernel.org/pub/scm/git/git.git
origin	git://git.kernel.org/pub/scm/git/git.git
me@host:git % git branch -r 
  mirror/html
  mirror/maint
  mirror/man
  mirror/master
  mirror/next
  mirror/pu
  mirror/todo
  origin/HEAD
  origin/html
  origin/maint
  origin/man
  origin/master
  origin/next
  origin/pu
  origin/todo
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;You can either switch to a remote branch with &lt;code&gt;checkout origin/todo&lt;/code&gt; or create a new branch based on some remote branch &lt;code&gt;checkout -b myownbrach origin/todo&lt;/code&gt;, the latter also sets up &amp;#8220;tracking&amp;#8221; which means that &lt;code&gt;push&lt;/code&gt; and &lt;code&gt;pull&lt;/code&gt; automatically use the branch &amp;#8220;todo&amp;#8221; at the remote repository &amp;#8220;origin&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Another very cool feature of Git (and of course others) is the ability to &amp;#8220;cherry-pick&amp;#8221;. That is, we could take the patches (commits) interesting to us and incorporate them into our own branch. To accomplish that task, there&amp;#8217;s &lt;code&gt;cherry-pick&lt;/code&gt; at our disposal. Simply choose the commit you&amp;#8217;d like to import from another branch and call &lt;code&gt;cherry-pick &amp;lt;commit&amp;gt;&lt;/code&gt; at the branch you&amp;#8217;d like to incorporate the patch (commit). Works like a charm.&lt;/p&gt;
&lt;h2&gt;How I use Git&lt;/h2&gt;
&lt;p&gt;Note that I just switched to Git, but since Mercurial was very similar I know most of the concepts to some degree.&lt;/p&gt;
&lt;p&gt;I use version control for most of my files, be it configuration files in my home directory which get shared across my laptop, desktop and work machine or letters I write. Of course Git isn&amp;#8217;t the best way to do everything, but it&amp;#8217;s a better way than not syncing my files at all.&lt;/p&gt;
&lt;p&gt;I have three &amp;#8220;work-machines&amp;#8221; which synchronise to a server accessible by all of my machines. For machine-specific files (in my home-dir for example) I made a special directory &amp;#8220;.machinedependent&amp;#8221; and created sub-folders for each machine. In this directories I put the configuration files I&amp;#8217;d like to be version controlled even if the are only interesting for one machine. Then I hard-link files and soft-link directories and I&amp;#8217;m done. Git handles this quite nicely.&lt;/p&gt;
&lt;p&gt;All of my coding projects are handled by Git and stored (for backup purposes and accessibility) on the mentioned server. I like the fact that my code is distributed across several machine nowhere near each other.  &lt;a href="http://jean-francois.richard.name/ghh/git-home-history.html"&gt;Git-home-history&lt;/a&gt; has some capabilities to produce encrypted archives of your work too, but I didn&amp;#8217;t dig into that by now.&lt;/p&gt;
&lt;p&gt;This, of course, didn&amp;#8217;t touch more than the bare surface of Git. Look at&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.git.or.cz"&gt;Git&amp;#8217;s Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html"&gt;Git&amp;#8217;s Tutorial&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.kernel.org/pub/software/scm/git/docs/user-manual.html"&gt;Git&amp;#8217;s User&amp;#8217;s Manual&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.kernel.org/pub/software/scm/git/docs/"&gt;Git&amp;#8217;s man pages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;for more information.&lt;/p&gt;
&lt;h2&gt;Converting from Mercurial to Git&lt;/h2&gt;
&lt;p&gt;I downloaded &lt;a href="http://github.com/vitaly/hg2git/tree/master"&gt;hg2git&lt;/a&gt; and converted all my repositories to Git (you should be in an empty directory and it may be an advantage to use &lt;a href="http://zsh.sourceforge.net/"&gt;zsh&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
for i in path/to/repos/*
do
  proj=$i:t
  mkdir $proj
  cd $proj
  git init
  hg2git.sh -r path/to/repos/$proj
  git checkout default
  git checkout -b master
  git branch -d default
  cd ..
done
&lt;/code&gt;
&lt;/pre&gt;
&lt;h2&gt;Missing some things from Mercurial&lt;/h2&gt;
&lt;p&gt;There are actually two features I somewhat miss in Git. First I cannot clone my local repository to a remote server without hassles (login to the remote server and create an empty project for example, or just scp the whole project over&amp;#8230; something like that).&lt;/p&gt;
&lt;p&gt;Second, Mercurial had very nice short-cuts. For example I could issue &lt;code&gt;hg st&lt;/code&gt; instead of &lt;code&gt;hg status&lt;/code&gt;, Git also has aliases, but you have to configure them on your own.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git config --global alias.ci "commit -a"&lt;/code&gt; adds an alias &amp;#8220;ci&amp;#8221; to commit all updated files (instead of adding each changed file individually to the index).&lt;/p&gt;
&lt;h2&gt;Which one is the right one?&lt;/h2&gt;
&lt;p&gt;Well the question of &amp;#8220;which version control software should I use&amp;#8221; comes up sooner or later (for some people &lt;strong&gt;so&lt;/strong&gt; late, they won&amp;#8217;t even notice it). I cannot tell you which one is right, the choice between centralized source code management and a distributed one is the first step and gives different possibilities (distributed is the way to go, &lt;span class="caps"&gt;IMHO&lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;Anyway, you&amp;#8217;ve got &lt;a href="http://en.wikipedia.org/wiki/List_of_revision_control_software"&gt;plenty to choose from&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For me only Darcs, Mercurial and (only recently) Git were interesting enough to dig deeper.  I dumped Darcs because installing it was not so easy, I&amp;#8217;m not root on all the machines I have access to and to compile a Haskell program into my home-dir was too much work for me.  And of course I heard about some nasty bugs in it&amp;#8230; .&lt;/p&gt;
&lt;p&gt;Mercurial was awesome (take a look at the &lt;a href="http://video.google.com/videoplay?docid=-7724296011317502612"&gt;Mercurial TechTalk&lt;/a&gt;), but Git won me over for absolutely no reason (mabye because it was envisioned by Linus Torvalds, maybe because I like C &lt;strong&gt;way&lt;/strong&gt; more than Python).&lt;/p&gt;
&lt;p&gt;I think most of the time we are not the ones to choose the version control software, anyway.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/LADr1GBkwoA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/git.html</feedburner:origLink></entry>
 
 <entry>
   <title>Mercurial Version Control Status in the ZSH Command Line Prompt</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/QDTIhuvQPeM/zsh_mercurial_notifier.html" />
   <updated>2008-08-07T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/tutorials/zsh_mercurial_notifier</id>
   <content type="html">&lt;p&gt;I sometimes forget to push or pull changes to or from a remote repository. To remedy the problem I wrote myself a little script to show me the status on the prompt.&lt;/p&gt;
&lt;p&gt;The script is written for zsh and Mercurial, but can be easily adapted to other version control systems (I guess).&lt;/p&gt;
&lt;p&gt;Everytime you change a directory the scripts looks up if there are uncommited changes, remote changes to be pulled or local patchsets to be pushed.&lt;/p&gt;
&lt;p&gt;The prompt of a directory within a project with uncommited changes would look something like this:&lt;/p&gt;
&lt;pre&gt;
  user@C2D:~/root-dir/subdir %            root-dir: U
&lt;/pre&gt;
&lt;p&gt;Possible states:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;U: Uncommited changes (use hg commit)&lt;/li&gt;
	&lt;li&gt;I: Incoming patchsets (use hg pull)&lt;/li&gt;
	&lt;li&gt;O: Outgoing patchsets (use hg push)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have configured Mercurial to automatically update my repository after a pull, but some people might wish to add another status for &amp;#8220;pending updates&amp;#8221; or something like that.&lt;/p&gt;
&lt;p&gt;The script uses &amp;#8220;&lt;code&gt;hg incoming -q&lt;/code&gt;&amp;#8221; or &amp;#8220;&lt;code&gt;hg outgoing -q&lt;/code&gt;&amp;#8221; to check for sets to be pulled or pushed, so you should configure the default paths in your &lt;code&gt;.hg/hgrc&lt;/code&gt; file for pulling or pushing like this:&lt;/p&gt;
&lt;pre&gt;
  [paths]
  default-push = ssh://yoursever.tld/Projects/PlanToTakeOverTheWorld/
  default = ssh://yourserver.tld/Projects/PlanToTakeOverTheWorld/
&lt;/pre&gt;
&lt;p&gt;Unfortunately there are a few problems:&lt;/p&gt;
&lt;p&gt;Accessing remote repositories over some network is costly. If you have a slow network connection you might want to temporarily switch off the remote status commands by using &amp;#8220;&lt;code&gt;export VCSNOREMOTE=true&lt;/code&gt;&amp;#8221; please note that &amp;#8220;&lt;code&gt;export VCSNOREMOTE=false&lt;/code&gt;&amp;#8221; has the same effect, in fact any string would switch off the remote commands. To enable them again use &amp;#8220;&lt;code&gt;export VCSNOREMOTE=&lt;/code&gt;&amp;#8221;.&lt;/p&gt;
&lt;p&gt;The second problem might be that you have to enter your credentials to access remote servers quite frequently. Use some sort of ssh-agent or something similar to avoid typing in your password all the time.&lt;/p&gt;
&lt;p&gt;The third thing to remember is that updating the status with &lt;strong&gt;every&lt;/strong&gt; prompt is useless, so I opted for updating after changing a directory (also if you type &lt;code&gt;cd .&lt;/code&gt;) but at least after 60 seconds.&lt;/p&gt;
&lt;p&gt;Installation: save anywhere on your disk and source it in your .zshrc file.&lt;/p&gt;
&lt;p&gt;Download: &lt;a href="http://blog.interlinked.org/static/files/vcs_status_prompt"&gt;vcs_status_prompt&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/QDTIhuvQPeM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/zsh_mercurial_notifier.html</feedburner:origLink></entry>
 
 <entry>
   <title>Free and Open Source Math Programs</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/vsMUAp9YGNI/open_source_math_programs.html" />
   <updated>2008-02-24T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/science/open_source_math_programs</id>
   <content type="html">&lt;p&gt;In this post I&amp;#8217;ll go through some of the most prominent math programs available with source code.&lt;/p&gt;
&lt;p&gt;This is by no means &amp;#8220;original&amp;#8221; work, I just collected the headlines and links to various mathematical software projects out there. This started with an offer of my University (Mathematica for 13 Euro), but I don&amp;#8217;t want to invest time in a tool I won&amp;#8217;t have (free, or almost free) access to for the rest of my life.&lt;/p&gt;
&lt;p&gt;The programs differ in their respective foci, the main areas are &lt;a href="http://en.wikipedia.org/wiki/Computer_algebra_system"&gt;Computer Algebra System&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Numerical_analysis"&gt;Numerical Analysis&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Statistics"&gt;Statistics&lt;/a&gt; and general purpose desktop calculators.&lt;/p&gt;
&lt;p&gt;My current choice is &lt;em&gt;&lt;span class="caps"&gt;SAGE&lt;/span&gt;&lt;/em&gt; and &lt;em&gt;R&lt;/em&gt; for my math and statistics needs. For simple calculations I usually use the calculator included with the OS or some interactive programming-shell (&lt;code&gt;ghci&lt;/code&gt; or &lt;code&gt;irb&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;Hybrid&lt;/h2&gt;
&lt;h3&gt;&lt;a href="http://www.sagemath.org/"&gt;&lt;span class="caps"&gt;SAGE&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span class="caps"&gt;SAGE&lt;/span&gt; is the new star on the open-source math sky. Essentially it is a &lt;span class="caps"&gt;CAS&lt;/span&gt; written in Python, but it provides interfaces to many math programs available. This includes commercial programs like Mathematica and Maple as well as free programs like Maxima, Octave or Singular.&lt;/p&gt;
&lt;p&gt;From the homepage:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Each interface requires that the corresponding software is installed on your computer. &lt;span class="caps"&gt;SAGE&lt;/span&gt; includes &lt;span class="caps"&gt;GAP&lt;/span&gt;, &lt;span class="caps"&gt;PARI&lt;/span&gt;, Singular, and Maxima, but does not include Octave (very easy to install), &lt;span class="caps"&gt;MAGMA&lt;/span&gt; (non-free), Maple (non-free), or Mathematica (non-free).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;SAGE&lt;/span&gt; runs as service on your server or desktop and you use your browser to interact with it (you can also use the command-line interface, though). It is very well documented and gives you access to the source code of the algorithms right within your browser.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use &lt;span class="caps"&gt;SAGE&lt;/span&gt; for studying a huge range of mathematics, including algebra, calculus, elementary to very advanced number theory, cryptography, numerical computation, commutative algebra, group theory, combinatorics, graph theory, and exact linear algebra.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The goal of the &lt;span class="caps"&gt;SAGE&lt;/span&gt; project, which started 2005, is to provide the &lt;a href="http://www.ddj.com/linux-open-source/204702621"&gt;best mathematical software in the world&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;SAGE&lt;/span&gt; is pretty large (on my Mac it uses 722MB right after the installation), but you can find even more (optional packages etc) at their homepage.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s also possible to interact with it via Texmacs or Emacs (again, available from their download page).&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;SAGE&lt;/span&gt; is available for Windows, Linux and Mac OS X.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.sagemath.org/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.sagemath.org/download.html"&gt;Download&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://www.sagenb.org/"&gt;Online Demo&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.sagemath.org/doc/html/tut/index.html"&gt;Tutorial&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.sagemath.org/documentation.html"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.flickr.com/photos/sagescreenshots/sets/72157603532209437/"&gt;Screenshots&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Computer Algebra System&lt;/h2&gt;
&lt;h3&gt;&lt;a href="http://maxima.sourceforge.net/"&gt;Maxima&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Maxima is a system for the manipulation of symbolic and numerical expressions, including differentiation, integration, Taylor series, Laplace transforms, ordinary differential equations, systems of linear equations, polynomials, and sets, lists, vectors, matrices, and tensors. Maxima yields high precision numeric results by using exact fractions, arbitrary precision integers, and arbitrarily precision floating point numbers. Maxima can plot functions and data in two and three dimensions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Maxima is very mature and stood the test of time. It started in 1982 and is &amp;#8220;free&amp;#8221; since 1998.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://maxima.sourceforge.net/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://maxima.sourceforge.net/download.shtml"&gt;Download&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://maxima.sourceforge.net/docs.shtml"&gt;Documentation/Tutorial&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://maxima.sourceforge.net/screenshots.shtml"&gt;Screenshots&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Maxima is included in &lt;span class="caps"&gt;SAGE&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://savannah.nongnu.org/projects/axiom/"&gt;Axiom&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Axiom is a general purpose Computer Algebra system. It is useful for doing mathematics by computer and for research and development of mathematical algorithms. It defines a strongly typed, mathematically correct type hierarchy. It has a programming language and a built-in compiler.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://page.axiom-developer.org/"&gt;Homepage&lt;/a&gt; or at &lt;a href="http://savannah.nongnu.org/projects/axiom/"&gt;Savannah&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://page.axiom-developer.org/axiom-website/download.html"&gt;Download&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://page.axiom-developer.org/axiom-website/documentation.html"&gt;Documentation/Tutorial&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://page.axiom-developer.org/axiom-website/screenshots.html"&gt;Screenshots&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href="http://yacas.sourceforge.net/homepage.html"&gt;Yacas&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;YACAS&lt;/span&gt; is an easy to use, general purpose Computer Algebra System, a program for symbolic manipulation of mathematical expressions. It uses its own programming language designed for symbolic as well as arbitrary-precision numerical computations. The system has a library of scripts that implement many of the symbolic algebra operations; new algorithms can be easily added to the library. &lt;span class="caps"&gt;YACAS&lt;/span&gt; comes with extensive documentation (hundreds of pages) covering the scripting language, the functionality that is already implemented in the system, and the algorithms we used.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://yacas.sourceforge.net/homepage.html"&gt;Homepage&lt;/a&gt; Downlaods, Screenshots, Tutorial, Manual and Demo are available there.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href="http://pari.math.u-bordeaux.fr/"&gt;&lt;span class="caps"&gt;PARI&lt;/span&gt;/GP&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;PARI&lt;/span&gt;/GP is a widely used computer algebra system designed for fast computations in number theory (factorizations, algebraic number theory, elliptic curves&amp;#8230;), but also contains a large number of other useful functions to compute with mathematical entities such as matrices, polynomials, power series, algebraic numbers etc., and a lot of transcendental functions. &lt;span class="caps"&gt;PARI&lt;/span&gt; is also available as a C library to allow for faster computations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://pari.math.u-bordeaux.fr/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://pari.math.u-bordeaux.fr/download.html"&gt;Download&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://pari.math.u-bordeaux.fr/doc.html"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class="caps"&gt;PARI&lt;/span&gt;/GP is included in &lt;span class="caps"&gt;SAGE&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://www.singular.uni-kl.de/"&gt;Singular&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;SINGULAR&lt;/span&gt; is a Computer Algebra System for polynomial computations with special emphasis on the needs of commutative algebra, algebraic geometry, and singularity theory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.singular.uni-kl.de/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.singular.uni-kl.de/download.html"&gt;Download&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.singular.uni-kl.de/Manual/latest/index.htm"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Singular is included in &lt;span class="caps"&gt;SAGE&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://www-gap.mcs.st-and.ac.uk/"&gt;&lt;span class="caps"&gt;GAP&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;GAP&lt;/span&gt; is a system for computational discrete algebra, with particular emphasis on Computational Group Theory. &lt;span class="caps"&gt;GAP&lt;/span&gt; provides a programming language, a library of thousands of functions implementing algebraic algorithms written in the &lt;span class="caps"&gt;GAP&lt;/span&gt; language as well as large data libraries of algebraic objects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www-gap.mcs.st-and.ac.uk/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www-gap.mcs.st-and.ac.uk/Download/index.html"&gt;Download&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www-gap.mcs.st-and.ac.uk/Doc/doc.html"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class="caps"&gt;GAP&lt;/span&gt; is included in &lt;span class="caps"&gt;SAGE&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://www.math.uiuc.edu/Macaulay2/"&gt;Macaulay2&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Macaulay 2 is a software system devoted to supporting research in algebraic geometry and commutative algebra.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.math.uiuc.edu/Macaulay2/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.math.uiuc.edu/Macaulay2/Downloads/index.html"&gt;Download&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.math.uiuc.edu/Macaulay2/Book/"&gt;Book&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Numerical Analysis/Computation&lt;/h2&gt;
&lt;h3&gt;&lt;a href="http://www.gnu.org/software/octave/"&gt;Octave&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;GNU&lt;/span&gt; Octave is a high-level language, primarily intended for numerical computations. It provides a convenient command line interface for solving linear and nonlinear problems numerically, and for performing other numerical experiments using a language that is mostly compatible with Matlab. It may also be used as a batch-oriented language.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.gnu.org/software/octave/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.gnu.org/software/octave/download.html"&gt;Download&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.gnu.org/software/octave/docs.html"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href="http://mathsrv.ku-eichstaett.de/MGF/homes/grothmann/euler/index.html"&gt;Euler&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Euler is a powerful interactive numerical laboratory. It quickly evaluates numerical functions, visualizes results, and allows to test and program numerical algorithms. The system can handle real, complex and interval numbers, vectors and matrices, and additionally a long data type for exact computation. Most routines are written in the high level Euler language and can be modified or extended by the user.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://mathsrv.ku-eichstaett.de/MGF/homes/grothmann/euler/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://mathsrv.ku-eichstaett.de/MGF/homes/grothmann/euler/euler_download.html"&gt;Download&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://mathsrv.ku-eichstaett.de/MGF/homes/grothmann/euler/sceenshots.html"&gt;Screenshots&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href="http://www.scilab.org/"&gt;Scilab&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Scilab is a scientific software package for numerical computations providing a powerful open computing environment for engineering and scientific applications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.scilab.org/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.scilab.org/download/"&gt;Download&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Statistics&lt;/h2&gt;
&lt;h3&gt;&lt;a href="http://www.r-project.org/"&gt;R&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you want to do some statistics there is no way around &amp;#8220;R&amp;#8221;. At least not in the free and open-source software world.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;R provides a wide variety of statistical (linear and nonlinear modelling, classical statistical tests, time-series analysis, classification, clustering, &amp;#8230;) and graphical techniques, and is highly extensible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think R is a tool everyone should be familiar with, at least with the most basic operations. Statistics is such an important every-day tool you can immediately put to work as soon as you know something, anything, about it.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.r-project.org/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://cran.r-project.org/manuals.html"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.cyclismo.org/tutorial/R/"&gt;Tutorial&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.r-project.org/screenshots/screenshots.html"&gt;Screenshots&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.r-project.org/doc/bib/R-books.html"&gt;Books&lt;/a&gt; (currently 53 books!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Command-Line/Desktop Calculator&lt;/h2&gt;
&lt;p&gt;Sometimes you just want to calculate very simple things, for this task a full fledged system isn&amp;#8217;t really appropriate.&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://www.gnu.org/software/bc/"&gt;bc&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;bc is an arbitrary precision numeric processing language. Syntax is similar to C, but differs in many substantial areas. It supports interactive execution of statements. bc is a utility included in the &lt;span class="caps"&gt;POSIX&lt;/span&gt; P1003.2/D11 draft standard.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.gnu.org/software/bc/"&gt;Homepage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.gnu.org/software/bc/manual/bc.html"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;bc is usually installed on any Linux/Unix system or available via its package management.&lt;/p&gt;
&lt;h3&gt;&amp;#8220;Other&amp;#8221; command-line/desktop calculators&lt;/h3&gt;
&lt;p&gt;Essentially you can use any interactive shell, like Python&amp;#8217;s &lt;code&gt;python&lt;/code&gt; or Ruby&amp;#8217;s &lt;code&gt;irb&lt;/code&gt; as well as Haskell&amp;#8217;s &lt;code&gt;ghci&lt;/code&gt; or &lt;code&gt;hugs&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;span class="caps"&gt;GUI&lt;/span&gt; Calculators&lt;/h3&gt;
&lt;p&gt;Despite the included Desktop Calculators there are some very fine products out there, here some pearls I could find:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Mac OS X
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="http://home.swiftdsl.com.au/~mattg/"&gt;Magic Number Machine&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;Linux
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="http://qalculate.sourceforge.net/"&gt;Qualculate!&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://calcoo.sourceforge.net/"&gt;Calcoo&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;Windows
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="http://calcoo.sourceforge.net/win/"&gt;Calcoo for Windows&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;Any suggestions?&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If nothing else, there is always &lt;a href="http://www.google.com/search?q=2%2B2*(9%5E2)"&gt;Google Calc&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/vsMUAp9YGNI" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/science/open_source_math_programs.html</feedburner:origLink></entry>
 
 <entry>
   <title>Emacs Basics</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/5WY6ezCEvp4/emacs.html" />
   <updated>2008-02-24T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/tutorials/emacs</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s been a while since I wrote my &lt;a href="http://blog.interlinked.org/tutorials/vim_tutorial.html"&gt;Vim Introduction and Tutorial&lt;/a&gt; (exactly one year). A lot happened between now and then, I chose to get a better feeling about Emacs for example.&lt;/p&gt;
&lt;p&gt;The reasons aren&amp;#8217;t easily explained; The most prominent reason is the awesome &lt;a href="http://www.gnu.org/software/auctex/"&gt;AucTex-mode&lt;/a&gt; since I&amp;#8217;m working heavily with LaTeX lately.&lt;/p&gt;
&lt;p&gt;Anyways, learning Vim &lt;strong&gt;and&lt;/strong&gt; Emacs is better than learning only one of them :-).&lt;/p&gt;
&lt;p&gt;Vim started in 1991 and is based on Bill Joy&amp;#8217;s Vi written in 1976/77. Emacs started as set of macros for the &lt;span class="caps"&gt;TECO&lt;/span&gt; editor 1976 and was rewritten in 1984 (&lt;span class="caps"&gt;GNU&lt;/span&gt; Emacs). So both editors are based on concepts invented more than 30 years ago and both editors are very unlikely to change any time soon.&lt;/p&gt;
&lt;p&gt;I still like Vim&amp;#8217;s way of doing things, for example the basic commands are very easy and very fast to reach.&lt;/p&gt;
&lt;p&gt;At first I wanted to compile something similar to my Vim Tutorial, but I ended up publishing just a few notes and more or less a cheat-sheet for Emacs. If you like it more &lt;em&gt;official&lt;/em&gt; look at the &lt;a href="http://www.gnu.org/software/emacs/tour/"&gt;Emacs Guided Tour&lt;/a&gt; and its very fine &lt;a href="http://www.gnu.org/software/emacs/manual/index.html"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The best way to get up and running with Emacs is the included tutorial (start by typing &lt;code&gt;C-h t&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m using &lt;a href="http://aquamacs.org/"&gt;Aquamacs&lt;/a&gt; on my Mac and &lt;span class="caps"&gt;GNU&lt;/span&gt; Emacs on Linux. Both use &lt;span class="caps"&gt;GNU&lt;/span&gt; Emacs 22 at its core, but especially Aquamacs provides some extensions to make it (almost) seamless on OS X.&lt;/p&gt;
&lt;h1&gt;Basic Concepts&lt;/h1&gt;
&lt;p&gt;You can&amp;#8217;t learn Emacs and lean back, every mode Emacs provides offers its own key bindings and has its own specialities you have to know.&lt;/p&gt;
&lt;p&gt;So, it doesn&amp;#8217;t matter if you use Vim for day-to-day tasks and Emacs for special purpose text editing (like typing LaTeX, or interacting with some math software). Only the most basic commands are the same for all modes.&lt;/p&gt;
&lt;h2&gt;Two things to remember&lt;/h2&gt;
&lt;p&gt;You can cancel any operation either by pressing &lt;code&gt;C-g&lt;/code&gt; or three times &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To exit Emacs, type &lt;code&gt;C-x C-c&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Major/Minor Modes&lt;/h2&gt;
&lt;p&gt;A Major Mode provides Key-Bindings, Indentation, Display, Syntax etc. There can be only &lt;strong&gt;one&lt;/strong&gt; Major Mode active at a given time. How would you mix two different syntax-highlighting schemes?&lt;/p&gt;
&lt;p&gt;A Minor Mode provides additional bindings and some other behavior. For example spell-correction, automatic line-breaks etc.&lt;/p&gt;
&lt;h2&gt;Emacs Lisp functions and key bindings&lt;/h2&gt;
&lt;p&gt;You can access &lt;strong&gt;all&lt;/strong&gt; functions of Emacs with: &lt;code&gt;M-x&lt;/code&gt; (that&amp;#8217;s &lt;code&gt;&amp;lt;Alt&amp;gt;-x&lt;/code&gt; or &lt;code&gt;&amp;lt;Meta&amp;gt;-x&lt;/code&gt; or &lt;code&gt;&amp;lt;Esc&amp;gt; x&lt;/code&gt; or &lt;code&gt;&amp;lt;Option&amp;gt;-x&lt;/code&gt; depending on your setup, preferences and terminology).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-x&lt;/code&gt; means pressing &lt;code&gt;Control&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; at the same time, &lt;code&gt;&amp;lt;Esc&amp;gt; x&lt;/code&gt; means pressing &lt;code&gt;Escape&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt; after another.&lt;/p&gt;
&lt;p&gt;There is no way to bind all functions to some key-combo and it might be impossible to remember the bindings. So, if you want to replace some string with some other string type &amp;#8220;&lt;code&gt;M-x repl&amp;lt;Tab&amp;gt;&amp;lt;Tab&amp;gt;&lt;/code&gt;&amp;#8221; and Emacs gives you possible completions, &amp;#8220;replace-string&amp;#8221; sounds good.&lt;/p&gt;
&lt;h2&gt;Emacs&amp;#8217; Architecture&lt;/h2&gt;
&lt;p&gt;Emacs has a small Lisp core written in C. But the &amp;#8220;meat&amp;#8221; of Emacs is the expansion-library written in Emacs Lisp. Essentially everything you do and write to extend and configure Emacs is written in Emacs Lisp.&lt;/p&gt;
&lt;p&gt;The Bookworm has an &lt;a href="http://blog.bookworm.at/2007/03/introduction-to-all-these-emacs.html"&gt;introduction to the Emacs introductions&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Undo/Redo&lt;/h2&gt;
&lt;p&gt;To undo almost every action you did, you can use either &lt;code&gt;undo&lt;/code&gt; as command or one of the following key-bindings: &lt;code&gt;C-/&lt;/code&gt;, &lt;code&gt;C-_&lt;/code&gt; or &lt;code&gt;C-x u&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Undo &amp;rarr; &lt;code&gt;C-/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To redo, you have to switch the &amp;#8220;undo-direction&amp;#8221; with &lt;code&gt;C-g&lt;/code&gt;, after that you can use the usual undo-key of your choice.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Switch undo-direction &amp;rarr; &lt;code&gt;C-g&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Basic Movement&lt;/h1&gt;
&lt;ul&gt;
	&lt;li&gt;Character movement
	&lt;ul&gt;
		&lt;li&gt;Up &amp;rarr; &lt;code&gt;C-p&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Down &amp;rarr; &lt;code&gt;C-n&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Left &amp;rarr; &lt;code&gt;C-f&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Right &amp;rarr; &lt;code&gt;C-b&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Page movement
	&lt;ul&gt;
		&lt;li&gt;Page Down &amp;rarr; &lt;code&gt;C-v&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Page Up &amp;rarr; &lt;code&gt;M-v&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Line movement
	&lt;ul&gt;
		&lt;li&gt;Start of Line &amp;rarr; &lt;code&gt;C-a&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;End of Line &amp;rarr; &lt;code&gt;C-e&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Sentence movement
	&lt;ul&gt;
		&lt;li&gt;Start of Sentence &amp;rarr; &lt;code&gt;M-a&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;End of Sentence &amp;rarr; &lt;code&gt;M-e&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Paragraph movement
	&lt;ul&gt;
		&lt;li&gt;Start of Paragraph &amp;rarr; &lt;code&gt;M-{&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;End of Paragraph &amp;rarr; &lt;code&gt;M-}&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Other
	&lt;ul&gt;
		&lt;li&gt;Start of File/Buffer &amp;rarr; &lt;code&gt;M-&amp;lt;&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;End of File/Buffer &amp;rarr; &lt;code&gt;M-&amp;gt;&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Search and Search &amp;amp; Replace&lt;/h1&gt;
&lt;h2&gt;Searching/Replacing&lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;Incremental Search forward &amp;rarr; &lt;code&gt;C-s&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Incremental Search backward &amp;rarr; &lt;code&gt;C-r&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Incremental Search forward with regular expressions &amp;rarr; &lt;code&gt;search-forward-regexp&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Incremental Search backward with regular expressions &amp;rarr; &lt;code&gt;search-backward-regexp&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Replace some string &amp;rarr; &lt;code&gt;replace-string&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Replace using regular expressions &amp;rarr; &lt;code&gt;replace-regexp&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Text Surgery&lt;/h1&gt;
&lt;ul&gt;
	&lt;li&gt;Deleting/Killing
	&lt;ul&gt;
		&lt;li&gt;Delete char forward &amp;rarr; &lt;code&gt;C-d&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Delete char backward &amp;rarr; &lt;code&gt;&amp;lt;Backspace&amp;gt;&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Kill word forward &amp;rarr; &lt;code&gt;M-d&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Kill word backward &amp;rarr; &lt;code&gt;M-&amp;lt;Backspace&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Kill to end of line &amp;rarr; &lt;code&gt;C-k&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Kill to end of sentence &amp;rarr; &lt;code&gt;M-k&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Transpose (switch elements)
	&lt;ul&gt;
		&lt;li&gt;Transpose chars &amp;rarr; &lt;code&gt;C-t&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Transpose words &amp;rarr; &lt;code&gt;M-t&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Transpose lines &amp;rarr; &lt;code&gt;C-x C-t&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Case-operations
	&lt;ul&gt;
		&lt;li&gt;Capitalize word &amp;rarr; &lt;code&gt;M-c&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Uppercase word &amp;rarr; &lt;code&gt;M-u&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Lowercase word &amp;rarr; &lt;code&gt;M-l&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;Text-completion &amp;rarr; &lt;code&gt;M-/&lt;/code&gt; (repeat to cycle through possible completions)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;New-Lines
	&lt;ul&gt;
		&lt;li&gt;New line &amp;rarr; &lt;code&gt;&amp;lt;Return&amp;gt;&lt;/code&gt; or &lt;code&gt;C-m&lt;/code&gt; (insert a CR before the cursor)&lt;/li&gt;
		&lt;li&gt;Open new Line &amp;rarr; &lt;code&gt;C-o&lt;/code&gt; (insert a CR after the cursor)&lt;/li&gt;
		&lt;li&gt;New line and indent &amp;rarr; &lt;code&gt;C-j&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I like to format my text so that no lines are longer than 78 characters. Either I use the minor mode &lt;code&gt;auto-fill-mode&lt;/code&gt; or I use &lt;code&gt;M-q&lt;/code&gt; to re-justify (fill) the current paragraph (necessary if you edit a paragraph after it was auto-filled).&lt;/p&gt;
&lt;h1&gt;Cut/Copy/Paste&lt;/h1&gt;
&lt;h2&gt;Basic commands&lt;/h2&gt;
&lt;p&gt;Maybe you noticed that I changed the terminology of deleting a character to killing a word. The difference is, that &amp;#8220;killed&amp;#8221; text is put into the &lt;strong&gt;Yank-Ring&lt;/strong&gt;. From this ring, you can get your text back (pasting, yank). The size of your yank-ring depends on your setup.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Yank &amp;rarr; &lt;code&gt;C-y&lt;/code&gt;, use &lt;code&gt;M-y&lt;/code&gt; to cycle through the various text-parts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;#8217;ve marked some text, use &lt;code&gt;C-w&lt;/code&gt; to cut the text, or &lt;code&gt;M-w&lt;/code&gt; to copy the text into the yank-ring:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Cut &amp;rarr; &lt;code&gt;C-w&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Copy &amp;rarr; &lt;code&gt;M-w&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Regions&lt;/h2&gt;
&lt;p&gt;To mark some text, use the mouse, or set a mark with &lt;code&gt;C-&amp;lt;Space&amp;gt;&lt;/code&gt; and move the cursor to the end point of the region. The text between the mark and the current cursor-position (also called point) is the &lt;strong&gt;region&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Set mark &amp;rarr; &lt;code&gt;C-&amp;lt;Space&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can jump between point and mark using &lt;code&gt;C-x C-x&lt;/code&gt;, this switches the mark and the point, so that your region remains intact.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Switch point and mark &amp;rarr; &lt;code&gt;C-x C-x&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;#8217;ve enabled the &lt;code&gt;transient-mark-mode&lt;/code&gt; Emacs highlights the region when you create it. As soon as you move the cursor, the region is still there, but the highlight is gone (verify with &lt;code&gt;C-x C-x&lt;/code&gt; for example).&lt;/p&gt;
&lt;h2&gt;Rectangles&lt;/h2&gt;
&lt;p&gt;The mark and point also specify a rectangle over your text (upper right and lower left edge).&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Kill the rectangle &amp;rarr; &lt;code&gt;C-x r k&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Yank the rectangle &amp;rarr; &lt;code&gt;C-x r y&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Insert space into the rectangle &amp;rarr; &lt;code&gt;C-x r o&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Replace text of the rectangle &amp;rarr; &lt;code&gt;C-x r t&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Clear rectangle (replace with space) &amp;rarr; &lt;code&gt;C-x r c&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is an interesting minor mode for additional rectangle-functionality called &lt;strong&gt;&lt;span class="caps"&gt;CUA&lt;/span&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h1&gt;Frames, Windows and Buffers&lt;/h1&gt;
&lt;p&gt;Emacs has the concept of Frames, Windows and Buffers. A Frame is a Window in the common sense, a Window is a part of the frame. For example if you split the screen of your Emacs frame, you got two windows within one frame.&lt;/p&gt;
&lt;p&gt;The last concept is the Buffer, it&amp;#8217;s simply a real or virtual file (virtual == not saved to disk).&lt;/p&gt;
&lt;p&gt;Buffer commands:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Load a file (buffer) &amp;rarr; &lt;code&gt;C-x C-f&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Show loaded buffers &amp;rarr; &lt;code&gt;C-x C-b&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Switch to another buffer &amp;rarr; &lt;code&gt;C-x b&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Close a buffer &amp;rarr; &lt;code&gt;C-x k&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Save a buffer &amp;rarr; &lt;code&gt;C-x C-s&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Frame commands:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Open new frame with file &amp;rarr; &lt;code&gt;C-x 5 f&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Close this frame &amp;rarr; &lt;code&gt;C-x 5 0&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Switch to other frame &amp;rarr; &lt;code&gt;C-x 5 o&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Window commands:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Split window vertically &amp;rarr; &lt;code&gt;C-x 2&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Split window horizontally &amp;rarr; &lt;code&gt;C-x 3&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Close all other windows &amp;rarr; &lt;code&gt;C-x 1&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Close this window &amp;rarr; &lt;code&gt;C-x 0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Minibuffer (the last line of your Emacs screen) is a buffer&lt;br /&gt;
itself, but has some specialities I wont go into now.&lt;/p&gt;
&lt;h1&gt;Getting Help from Emacs&lt;/h1&gt;
&lt;p&gt;You could fill some very big books with Emacs-specific information, but Emacs calls itself a &amp;#8220;self-documenting&amp;#8221; editor. This means that the documentation reflects exactly how your Emacs is configured. If you change some key-bindings, the documentation reflects this changes and displays the right key-combo in the help files.&lt;/p&gt;
&lt;p&gt;Some hints on how to get going using the help-system:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Show information on the current mode(s) &amp;rarr; &lt;code&gt;C-h m&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Describe the command bound to the given key &amp;rarr; &lt;code&gt;C-h k&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Search for a function &amp;rarr; &lt;code&gt;C-h a&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Describe all key-bindings of the current mode(s) &amp;rarr; &lt;code&gt;C-h b&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Further Information&lt;/h1&gt;
&lt;p&gt;Steve Yegge has some intersting articles on Emacs:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://steve.yegge.googlepages.com/effective-emacs"&gt;Effective Emacs&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://steve-yegge.blogspot.com/2006/06/shiny-and-new-emacs-22.html"&gt;Shiny and new Emacs 22&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class="caps"&gt;IBM&lt;/span&gt; has some nice &lt;a href="http://www.ibm.com/developerworks/views/aix/libraryview.jsp?search_by=emacs+editing+environment"&gt;Emacs tutorials too&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://www.emacswiki.org"&gt;EmacsWiki&lt;/a&gt; is another excellent source for Emacs related howtos, downloads and &amp;#8211; to some extend &amp;#8211; discussions.&lt;/p&gt;
&lt;h1&gt;Wish&lt;/h1&gt;
&lt;p&gt;I&amp;#8217;d wish that Vim and Emacs would merge. That I could take advantage of Emacs&amp;#8217; awesome tool-support and Vim&amp;#8217;s awesome way of editing small junks of text. I know there is Viper-mode and Vimpulse, but both are not exactly what I want. Viper-mode is plain Vi, and Vimpulse is early in development.&lt;/p&gt;
&lt;p&gt;Is there a way to integrate a Vim window into Emacs without emulating and reimplementing the features?&lt;/p&gt;
&lt;p&gt;For the time being, I&amp;#8217;ll have to switch between the environments. Vim as my default-editor and Emacs for special purpose editing.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/5WY6ezCEvp4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/emacs.html</feedburner:origLink></entry>
 
 <entry>
   <title>Addendum to "Time Machine for every Unix out there"</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/GHODat8KHgY/rsync_addendum.yaml.html" />
   <updated>2007-12-06T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/tutorials/rsync_addendum.yaml</id>
   <content type="html">&lt;p&gt;My article about using rsync to mimic the behavior of Apple&amp;#8217;s Time Machine generated a lot of traffic, and more important, a lot of feedback.&lt;/p&gt;
&lt;p&gt;In this article I&amp;#8217;ll summarize and try to clarify a few things.&lt;/p&gt;
&lt;p&gt;First of all: I didn&amp;#8217;t invent any of the things I&amp;#8217;ve written in the &lt;a href="http://blog.interlinked.org/tutorials/rsync_time_machine.html"&gt;article&lt;/a&gt;! All I did was to write it up in a manner I could understand it. The rsync developer(s) included the feature(s) for a specific purpose which might be exactly what we do now. But this was obvious, I hope.&lt;/p&gt;
&lt;h1&gt;Time Machine and Performance&lt;/h1&gt;
&lt;p&gt;&lt;a href="http://arstechnica.com/reviews/os/mac-os-x-10-5.ars/14"&gt;Ars Technica&lt;/a&gt; has a very deep review of the new features of Leopard, including Time Machine.&lt;/p&gt;
&lt;p&gt;Interestingly they do very much the same as I did in my script &amp;#8211; each Backup gets its own folder and there is a link to the latest.&lt;/p&gt;
&lt;p&gt;Some readers complained that Time Machine looks only at the changed files, where my script has to look at each file on the disk. For me, the difference is negligible. Apple introduced hard-links to &lt;strong&gt;directories&lt;/strong&gt;, which saves a lot of time and a bit of space. Unfortunately this feature isn&amp;#8217;t availabel on plain Unix, but it&amp;#8217;s a neat trick!&lt;/p&gt;
&lt;h1&gt;Restoring the Files&lt;/h1&gt;
&lt;p&gt;Since we make full backups each time, you have your whole and complete directory structure in that Backup-directories.&lt;/p&gt;
&lt;p&gt;Restoring a file is merely a simple &lt;code&gt;copy&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;Or, if you want to restore the whole filesystem, use:&lt;/p&gt;
&lt;code&gt;rsync -avz --delete host:/Backup/scurrent/ /target/&lt;/code&gt;
&lt;p&gt;But keep in mind that &lt;strong&gt;&amp;#8212;delete&lt;/strong&gt; removes any file which is not in the backup!&lt;/p&gt;
&lt;h1&gt;Removing old Backups&lt;/h1&gt;
&lt;p&gt;Another huge advantage of full backups is: &lt;em&gt;you can delete any backup you don&amp;#8217;t need anymore&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Of course each backup-directory takes space, if only for the hard-links and directory structure. Cleaning up the backups is a breeze: just delete the directories you don&amp;#8217;t need anymore. For example you could delete all directories older than 2 months or keep one week full, then only the monday backup. There are plenty of possibilities.&lt;/p&gt;
&lt;h1&gt;Other Tools&lt;/h1&gt;
&lt;p&gt;Many people suggested many interesting tools for doing backups. My argument against using such tools is that rsync is everywhere!&lt;/p&gt;
&lt;p&gt;You find rsync in the smallest Linux distributions (like &lt;a href="http://damnsmalllinux.org/"&gt;&lt;span class="caps"&gt;DSL&lt;/span&gt;&lt;/a&gt;), on PDAs like the &lt;a href="http://www.killefiz.de/zaurus/search.php?q=rsync&amp;amp;x=0&amp;amp;y=0"&gt;Zaurus&lt;/a&gt;, on Windows using &lt;a href="http://www.cygwin.com/"&gt;Cygwin&lt;/a&gt; and also on Nokia&amp;#8217;s Internet Tablets.&lt;/p&gt;
&lt;p&gt;One backup strategy for all your devices!&lt;/p&gt;
&lt;h1&gt;Space Requirements for the Links&lt;/h1&gt;
&lt;p&gt;Nothing in life is free, but the space used by the hardlinks for the backup is marginal. It is also dependent on the filesystem you use, ReiserFS seems to do a good job in packing more links in one cluster. But hey, these things are &lt;strong&gt;Backups&lt;/strong&gt; you throw away space anyways!&lt;/p&gt;
&lt;h1&gt;Colon&lt;/h1&gt;
&lt;p&gt;There is one particular problem using a colon in the script: some operating systems don&amp;#8217;t like them.&lt;/p&gt;
&lt;p&gt;Here an updated version of the script without colons:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
 #!/bin/sh

 date=`date "+%Y-%m-%dT%H_%M_%S"`
 rsync -azPE --link-dest=PATHTOBACKUP/current $SOURCE $HOST:PATHTOBACKUP/back-$date \
   &amp;amp;&amp;amp; ssh $HOST "rm PATHTOBACKUP/current \
   &amp;amp;&amp;amp; ln -s back-$date PATHTOBACKUP/current"
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Another slight change in the script is, that all commands are connected with &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;. This means the next command is only done when the previous command returned no error.&lt;/p&gt;
&lt;p&gt;Of course, if anything messes up the &amp;#8220;current&amp;#8221; link, the script just makes another full backup without the links to the previous version.&lt;/p&gt;
&lt;h1&gt;Extended Attributes on OS X&lt;/h1&gt;
&lt;p&gt;One user suggested the addition of the &lt;code&gt;-E&lt;/code&gt; parameter on Mac OS X. If you use the parameter on non-OS X machines it&amp;#8217;s more or less redundant (&lt;code&gt;-a&lt;/code&gt; contains executability), but on OS X some additional information is backed up.&lt;/p&gt;
&lt;p&gt;Just use it.&lt;/p&gt;
&lt;h1&gt;Windows&lt;/h1&gt;
&lt;p&gt;Some users reported success with this strategy on Windows. I&amp;#8217;m happy that we now have a unified backup strategy for all major operating systems without paying a single cent.&lt;/p&gt;
&lt;p&gt;You have to use Cygwin to install rsync (there are binaries without the whole Cygwin on the net, &lt;a href="http://optics.ph.unimelb.edu.au/help/rsync/rsync_pc1.html"&gt;here for example&lt;/a&gt;).&lt;/p&gt;
&lt;h1&gt;Measuring the Space Requirements&lt;/h1&gt;
&lt;p&gt;To lookup how much space your particular backups need, simply issue &lt;code&gt;du -shc back-*&lt;/code&gt;. This prints each backup directory with its real memory usage:&lt;/p&gt;
&lt;pre&gt;
  me@myserver:Backups % du -shc back-*                                                                                                               
  406M  back-2007-11-12T12:00:00
  6.8M  back-2007-11-13T20:28:56
  189M  back-2007-11-13T23:42:54
  2.6G  back-2007-11-14T08:15:43
  1.8M  back-2007-11-15T20:07:07
  7.9M  back-2007-11-18T23:57:09
  11M back-2007-11-19T21:53:34
  2.6M  back-2007-11-21T18:57:40
  2.1M  back-2007-11-21T19:11:02
  11M back-2007-11-22T01:19:38
  1.9M  back-2007-11-22T11:05:17
  19M back-2007-11-22T18:37:56
  7.4M  back-2007-11-22T22:45:04
  8.5M  back-2007-11-22T22:51:29
  9.2M  back-2007-11-24T12:45:12
  4.2M  back-2007-11-24T17:30:38
  11M back-2007-11-25T00:41:19
  1.9M  back-2007-11-27T20:41:40
  317M  back-2007-12-03T10:19:07
  12M back-2007-12-05T11:51:19
  3.6G  total
  me@myserver:Backups % 
&lt;/pre&gt;
&lt;p&gt;As you can see, the smallest backup (obviously without any changed file) requires 1.8MB.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/GHODat8KHgY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/rsync_addendum.yaml.html</feedburner:origLink></entry>
 
 <entry>
   <title>Time Machine for every Unix out there</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/UhiwBAxiiK8/rsync_time_machine.html" />
   <updated>2007-11-13T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/tutorials/rsync_time_machine</id>
   <content type="html">&lt;p&gt;&lt;a href="http://rsync.samba.org"&gt;rsync&lt;/a&gt; is one of the tools that have gradually infiltrated my day to day tool-box (aside Vim and Zsh).&lt;/p&gt;
&lt;p&gt;Using rsync it&amp;#8217;s very easy to mimic Mac OS X new feature called Time Machine. In this article I&amp;#8217;ll show how to do it, but there is still a nice &lt;span class="caps"&gt;GUI&lt;/span&gt; missing &amp;#8211; for those who like it shiny.&lt;/p&gt;
&lt;h2&gt;What Time Machine does&lt;/h2&gt;
&lt;p&gt;Time Machine makes a snapshot of your files every hour. The files are usually stored on a external hard drive connected to your Mac via &lt;span class="caps"&gt;USB&lt;/span&gt; or Firewire. Earlier Leopard versions (&lt;span class="caps"&gt;ADC&lt;/span&gt; preview versions) had the ability to make the backups to a remote drive (I&amp;#8217;ve heard).&lt;/p&gt;
&lt;p&gt;So if you lose a file, or did a devastating change to one of your files, simply go back in time until you find your file or a version that&amp;#8217;s not corrupted.&lt;/p&gt;
&lt;p&gt;Incrementally backing up all files every hour so that you can access them in reversed chronological order isn&amp;#8217;t that hard with standard Unix utilities like rsync. The only missing thing is a nice &lt;span class="caps"&gt;GUI&lt;/span&gt; for which Apple is known to be quite good at.&lt;/p&gt;
&lt;h2&gt;Making full backups in no time every hour&lt;/h2&gt;
&lt;p&gt;You can use this method to make a backup every hour or every ten minutes if you like. There are many many features you can tune or configure to your own taste &amp;#8211; excluding files that are larger than 1GB for example.&lt;/p&gt;
&lt;p&gt;So, here the command to make the backup:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;rsync -aP --link-dest&lt;span class="o"&gt;=&lt;/span&gt;PATHTO/&lt;span class="nv"&gt;$PREVIOUSBACKUP&lt;/span&gt; &lt;span class="nv"&gt;$SOURCE&lt;/span&gt; &lt;span class="nv"&gt;$CURRENTBACKUP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lets go through the parameters step by step.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; means Archive and includes a bunch of parameters to recurse directories, copy symlinks as symlinks, preserve permissions, preserve modification times, preserve group, preserve owner, and preserve device files. You usually want that option for all your backups.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;-P&lt;/code&gt; allows rsync to continue interrupted transfers and show a progress status for each file. This isn&amp;#8217;t really necessary but I like it.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;--link-dest&lt;/code&gt; this is a neat way to make full backups of your computers without losing much space. rsync links unchanged files to the previous backup (using hard-links, see below if you don&amp;#8217;t know hard-links) and only claims space for changed files. This only works if you have a backup at hand, otherwise you have to make at least one backup beforehand.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;PATHTO/$PREVIOUSBACKUP&lt;/code&gt; is the path to the previous backup for linking. Note: if you delete this directory, &lt;strong&gt;no other backup is harmed&lt;/strong&gt; because rsync uses &lt;strong&gt;hard-links&lt;/strong&gt; and the operating system (or filesystem) takes care of releasing space if no link points to that region anymore.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;$SOURCE&lt;/code&gt; is the directory you&amp;#8217;d like to backup.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;$CURRENTBACKUP&lt;/code&gt; is the directory to which you&amp;#8217;d like to make the backup. This should be a &lt;strong&gt;non-existing directory&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As said earlier, rsync has many many features. To exclude files over a certain size for example, use the option &lt;code&gt;--max-size&lt;/code&gt; (unfortunately this is not available on the rsync version shipped with Mac OS X Leopard). The man page or the &lt;a href="http://rsync.samba.org/documentation.html"&gt;documentation&lt;/a&gt; can give you plenty of ideas in this direction.&lt;/p&gt;
&lt;p&gt;So much for the theory of the most important command for our purpose. Here a simple script that makes an incremental backup every time you call it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="nv"&gt;date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;date &lt;span class="s2"&gt;&amp;quot;+%Y-%m-%dT%H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
rsync -aP --link-dest&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/Backups/current /path/to/important_files &lt;span class="nv"&gt;$HOME&lt;/span&gt;/Backups/back-&lt;span class="nv"&gt;$date&lt;/span&gt;
rm -f &lt;span class="nv"&gt;$HOME&lt;/span&gt;/Backups/current
ln -s back-&lt;span class="nv"&gt;$date&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/Backups/current
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The script creates a file called &amp;#8220;back&amp;#8221; appended by the current date and time, for example &lt;code&gt;back-2007-11-13T22:03:32&lt;/code&gt; which contains the &lt;strong&gt;full backup&lt;/strong&gt;. Then there is a symbolic link called &amp;#8220;current&amp;#8221; which points to the most recent directory. This directory-link is used for the &lt;code&gt;--link-dest&lt;/code&gt; parameter.&lt;/p&gt;
&lt;p&gt;You should look at the &lt;code&gt;--exclude&lt;/code&gt; parameter (or better, &lt;code&gt;--exclude-from=&lt;/code&gt; parameter) and learn how to exclude certain files or directories from the backup (you shouldn&amp;#8217;t backup your backup for example).&lt;/p&gt;
&lt;p&gt;The script above only works on the local machine because making links on a remote machine needs some extra work. But not much:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="nv"&gt;date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;date &lt;span class="s2"&gt;&amp;quot;+%Y-%m-%dT%H:%M:%S&amp;quot;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
rsync -azP --link-dest&lt;span class="o"&gt;=&lt;/span&gt;PATHTOBACKUP/current &lt;span class="nv"&gt;$SOURCE&lt;/span&gt; &lt;span class="nv"&gt;$HOST&lt;/span&gt;:PATHTOBACKUP/back-&lt;span class="nv"&gt;$date&lt;/span&gt;
ssh &lt;span class="nv"&gt;$HOST&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;rm -f PATHTOBACKUP/current &amp;amp;&amp;amp; ln -s back-$date PATHTOBACKUP/current&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;-f&lt;/code&gt; parameter for the &lt;code&gt;rm&lt;/code&gt; command is used to supress error messages if the &lt;code&gt;current&lt;/code&gt; directory is not present, which would in turn prevent the link to be created.&lt;/p&gt;
&lt;p&gt;To get that working you either use a public/private key authentication scheme or something else to avoid typing in your password. Another possibility is, of course, to mount the remote file-system on the local computer using the above script.&lt;/p&gt;
&lt;p&gt;On my setup the script takes about 6 seconds to synchronize 46968 files and 29GB &amp;#8211; this takes 20MB for the file structure (with no actual files to transfer of course). But afterwards, I have a complete backup of my system in a new directory.&lt;/p&gt;
&lt;p&gt;On a much bigger setup (1.2 million files and 50GB of data) the backup takes about 30 minutes and takes about 3GB of space (just for links!), so it isn&amp;#8217;t exactly &lt;strong&gt;free&lt;/strong&gt;, but very convenient.&lt;/p&gt;
&lt;p&gt;The space needed for the backup is determined by the shape of your directory structure. On the larger setup I have lots of Maildirs and a very deep directory structure so it takes much more space than my home-directory backup above. 3GB is quite a lot, but 20MB doesn&amp;#8217;t hurt.&lt;/p&gt;
&lt;h2&gt;Advanced &lt;code&gt;rsync&lt;/code&gt; parameters&lt;/h2&gt;
&lt;p&gt;Additional to the parameters described above, I usually employ a combination of these parameters in my backup:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;--delete&lt;/code&gt; and &lt;code&gt;--delete-excluded&lt;/code&gt; this tells rsync to remove files from my backups either if they are gone on my local machine, or if I decided to exclude them from my backup.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;--exclude-from=FILE&lt;/code&gt; the file specified here is a simple list of directories of files (one per line) which should &lt;strong&gt;not&lt;/strong&gt; be backed up. My &lt;code&gt;Trash&lt;/code&gt; folder oder some &lt;code&gt;.cache&lt;/code&gt; folders are candidates for this file.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;-P&lt;/code&gt; is used to give more information on how far the backup is, and how many files are to be backed up. Additional it could resume an interrupted transfer (which doesn&amp;#8217;t apply here because we create a blank backup each time we call the script).&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;-x&lt;/code&gt; this one is &lt;strong&gt;important&lt;/strong&gt; because it prohibits rsync to go beyond the local filesystem. For example if you backup you Linux-root partition, you should not include the /proc directory because rsync will get stuck in it. &lt;code&gt;-x&lt;/code&gt; excludes all mounted filesystems from the backup which is probably what you want in most cases.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Hard-Links&lt;/h2&gt;
&lt;p&gt;Each file in a directory is a link to the actual data on your hard-disk. The file-system keeps track of how many links to a area point, and only if the last link is deleted, the whole area gets deleted (in contrast to soft-links, these are pointers to the file-name, not the contents).&lt;/p&gt;
&lt;p&gt;Here an illustration of two backups with three files each. &lt;code&gt;File1&lt;/code&gt; and &lt;code&gt;File2&lt;/code&gt; are the &lt;em&gt;same&lt;/em&gt; in both backups, only &lt;code&gt;File3&lt;/code&gt; changed between &lt;code&gt;Backup1&lt;/code&gt; and &lt;code&gt;Backup2&lt;/code&gt;. So in &lt;code&gt;Backup2&lt;/code&gt;, &lt;code&gt;File3 (changed)&lt;/code&gt; has to point to a different area than &lt;code&gt;File3&lt;/code&gt; in &lt;code&gt;Backup1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/hardlinks.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;BTW&lt;/span&gt;, there is a &lt;a href="http://code.google.com/p/flyback/"&gt;nice project for Linux&lt;/a&gt; out there which provides the same functionality as Time Machine including a nice &lt;span class="caps"&gt;GUI&lt;/span&gt; which is also based on &lt;strong&gt;&lt;code&gt;rsync&lt;/code&gt;&lt;/strong&gt; and the procedure presented here.&lt;/p&gt;
&lt;h2&gt;The End&lt;/h2&gt;
&lt;p&gt;Credit: The initial idea for this approach came from &lt;a href="http://www.mikerubel.org/computers/rsync_snapshots/"&gt;Mike Rubel &amp;#8211; rsync snapshots&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also interesting if you have to cope with Windows: &lt;a href="http://www.softlab.ntua.gr/~ttsiod/backup.html"&gt;Optimal remote backups with rsync over Samba&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are quite a few approaches out there which more or less do the same, but rsync is available on virtually every Unix out there (even the &lt;a href="http://damnsmalllinux.org/"&gt;&lt;span class="caps"&gt;DSL&lt;/span&gt;&lt;/a&gt; with its 50MB footprint includes rsync). So using other tools might be more convenient, but I&amp;#8217;ll stick with the omnipresent rsync.&lt;/p&gt;
&lt;p&gt;rsync offers the possibility to store only the differences to the previous backup (using &lt;code&gt;--compare-dest&lt;/code&gt; which should point to a full-backup instead of &lt;code&gt;--link-dest&lt;/code&gt;). It then doesn&amp;#8217;t make links to the unchanged files, it just leaves them out. This way you get an incremental backup without the &amp;#8220;directory-overhead&amp;#8221; of the &lt;code&gt;--link-dest&lt;/code&gt; approach. &lt;strong&gt;But&lt;/strong&gt; you have to be &lt;strong&gt;extremely&lt;/strong&gt; cautious which one of older backups you delete because the newer backups just don&amp;#8217;t contain some of these files (think of full-backups as checkpoints)! Using the &lt;code&gt;--link-dest&lt;/code&gt; you can delete all backups but the last and you still got all the files, so I&amp;#8217;m happy to pay 20MB per backup for this safety.&lt;/p&gt;
&lt;h2&gt;Full script&lt;/h2&gt;
&lt;p&gt;Here my full script with additional features:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="nv"&gt;date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;date &lt;span class="s2"&gt;&amp;quot;+%Y-%m-%dT%H_%M_%S&amp;quot;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/user/

rsync -azP &lt;span class="se"&gt;\&lt;/span&gt;
  --delete &lt;span class="se"&gt;\&lt;/span&gt;
  --delete-excluded &lt;span class="se"&gt;\&lt;/span&gt;
  --exclude-from&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.rsync/exclude &lt;span class="se"&gt;\&lt;/span&gt;
  --link-dest&lt;span class="o"&gt;=&lt;/span&gt;../current &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;$HOME&lt;/span&gt; user@backupserver:Backups/incomplete_back-&lt;span class="nv"&gt;$date&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ssh user@backupserver &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;mv Backups/incomplete_back-$date Backups/back-$date \&lt;/span&gt;
&lt;span class="s2"&gt;  &amp;amp;&amp;amp; rm -f Backups/current \&lt;/span&gt;
&lt;span class="s2"&gt;  &amp;amp;&amp;amp; ln -s back-$date Backups/current&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/UhiwBAxiiK8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/rsync_time_machine.html</feedburner:origLink></entry>
 
 <entry>
   <title>XML as human interface and DSLs</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/2NFhyCADpiY/human_interface.html" />
   <updated>2007-10-30T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/misc/human_interface</id>
   <content type="html">&lt;p&gt;While reading &amp;#8220;The Definitive &lt;a href="http://www.antlr.org/"&gt;&lt;span class="caps"&gt;ANTLR&lt;/span&gt;&lt;/a&gt; Reference&amp;#8221; by &lt;a href="http://www.cs.usfca.edu/~parrt/"&gt;Terence Parr&lt;/a&gt; I encountered this quote. I&amp;#8217;m a bit sceptic about &lt;span class="caps"&gt;XML&lt;/span&gt; beyond its use of data exchange, so the quote has completely won me over for the book.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Don&amp;#8217;t be afraid to build a human-readable configuration file (I implore everyone to please stop using &lt;span class="caps"&gt;XML&lt;/span&gt; as a human interface!) or to build domain-specific languages to make yourself more efficient. Designing new languages and building translators for existing languages, when appropriate, is the hallmark of a sophisticated developer. &amp;#8212; Terence Parr, The Definitive &lt;span class="caps"&gt;ANTLR&lt;/span&gt; Reference, Page 23.&lt;/p&gt;
&lt;/blockquote&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/2NFhyCADpiY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/misc/human_interface.html</feedburner:origLink></entry>
 
 <entry>
   <title>Linux peripheral devices configuration</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/fM9Aa1da1y8/linux.html" />
   <updated>2007-09-01T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/tutorials/linux</id>
   <content type="html">&lt;p&gt;This weekend I tried to get my new keyboard (Microsoft Ergonomic Keyboard 4000) and my Logitech MX1000 Laser mouse to work properly. The Keyboard has many extra-keys I didn&amp;#8217;t bother to count, and the mouse has 12 buttons which can be very useful at times.&lt;/p&gt;
&lt;p&gt;Almost accidently I solved a bugging performance problem with the Firefox browser.  It was incredibly slow when opening Google Spreadsheets, well the whole system was incredibly slow while loading the spreadsheet&amp;#8230; .&lt;/p&gt;
&lt;h1&gt;Configuring the Microsoft Ergonomic Keyboard 4000 and the MX1000 Laser mouse&lt;/h1&gt;
&lt;p&gt;Most of the information I used to get my new keyboard working (except of 6 keys) came from the &lt;a href="http://gentoo-wiki.com/HOWTO_Microsoft_Natural_Ergonomic_Keyboard_4000"&gt;Gentoo-Wiki&lt;/a&gt; and the &lt;a href="http://ubuntuforums.org/showthread.php?t=229559"&gt;Ubuntu-Forum&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What you need is the&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.22.6.tar.bz2"&gt;Linux Kernel 2.6.22-6&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://ubuntuforums.org/attachment.php?attachmentid=36547&amp;amp;d=1182884449"&gt;MS Ergonomic Keyboard 4k Patch 0.5.1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Make sure that you get the right version of the patch for your Kernel (in case that 2.6.22 is outdated).&lt;/p&gt;
&lt;p&gt;Extract the Kernel, patch it (&lt;code&gt;patch -p1 &amp;lt; hid.patch&lt;/code&gt;) and compile it. I assume you&amp;#8217;ve got some experience compiling a Kernel (just follow the instructions at the &lt;a href="http://ubuntuforums.org/showthread.php?t=229559"&gt;Ubuntu-Forum&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Now for the configuration, I didn&amp;#8217;t follow the Gentoo-Wiki guide and didn&amp;#8217;t hack my xkb configuration because I couldn&amp;#8217;t see any advantages&amp;#8230; it seems that the &amp;#8220;evdev&amp;#8221; XkbModel does the right thing (if you don&amp;#8217;t set the Model to evdev, the keys are really messed up).&lt;/p&gt;
&lt;p&gt;I used the Gnome Keyboard-Shortcuts program to assign functionality to the keys. The keys I couldn&amp;#8217;t get to work are the special keys 1, 2, 3, 4, 5, Fav, and Zoom-In (Zoom-In is recognized by X, but is already assigned). Since I use GMail for mail I assigned the Mail-button to &lt;code&gt;firefox "http://www.gmail.com"&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The mouse is equally simple, follow the &lt;a href="http://blog.blackdown.de/2006/01/15/updated-logitech-mx1000-configuration/"&gt;instructions here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here the /etc/X11/xorg.conf config (relevant parts):&lt;/p&gt;
&lt;pre&gt;
Section "InputDevice"
    Identifier     "Keyboard Ergo. 4000 1"
    Driver         "evdev"
    Option         "Protocol" "evdev"
    Option         "Device" "/dev/input/event1"
    Option         "CoreKeyboard"
    Option         "XkbRules" "xorg"
    Option         "XkbModel" "evdev"
    Option         "XkbLayout" "us"
EndSection

Section "InputDevice"
    Identifier     "Keyboard Ergo. 4000 2"
    Driver         "evdev"
    Option         "Protocol" "evdev"
    Option         "Device" "/dev/input/event2"
    Option         "XkbRules" "xorg"
    Option         "XkbModel" "evdev"
    Option         "XkbLayout" "us"
EndSection

Section "InputDevice"
    Identifier     "MX1000"
    Driver         "evdev"
    Option         "CorePointer"
    Option         "Device" "/dev/input/event0"
    Option         "Buttons" "12"
    Option         "Resolution" "800"
EndSection

[...]

Section "ServerLayout"
    Identifier     "Default Layout"
    Screen         "Default Screen" 0 0
    InputDevice    "Keyboard Ergo. 4000 1" "CoreKeyboard"
    InputDevice    "Keyboard Ergo. 4000 2" "SendCoreEvents"
    InputDevice    "MX1000"
EndSection
&lt;/pre&gt;
&lt;p&gt;The udev rules to fix the keyboard to event1 and event2 (/etc/udev/rules.d/10-nek4k.rules, the &lt;span class="caps"&gt;UID&lt;/span&gt; should not differ from yours):&lt;/p&gt;
&lt;pre&gt;
KERNEL=="event*",SYSFS{modalias}=="usb:v045Ep00DBd0173dc00dsc00dp00ic03isc01ip01", MODE="0644", NAME="input/event1"
KERNEL=="event*",SYSFS{modalias}=="usb:v045Ep00DBd0173dc00dsc00dp00ic03isc00ip00", MODE="0644", NAME="input/event2"
&lt;/pre&gt;
&lt;p&gt;The udev rules for the mouse (/etc/udev/rules.d/11-mx1000.rules):&lt;/p&gt;
&lt;pre&gt;
KERNEL=="event*",SYSFS{modalias}=="usb:v046DpC50Ed2500dc00dsc00dp00ic03isc01ip02", MODE="0644", NAME="input/event0"
&lt;/pre&gt;
&lt;p&gt;The ~/.xbindkeysrc configuration I use simply activates the &amp;#8220;Forward&amp;#8221; &amp;#8220;Backward&amp;#8221; functionality (thumb buttons):&lt;/p&gt;
&lt;pre&gt;
# Backward and Forward buttons
"xvkbd -text "\[Alt_L]\[Left]""
  m:0x10 + b:8
"xvkbd -text "\[Alt_L]\[Right]""
  m:0x10 + b:9
&lt;/pre&gt;
&lt;p&gt;This maps the mouse button 8 to &lt;code&gt;Alt-Left&lt;/code&gt;, and button 9 to &lt;code&gt;Alt-Right&lt;/code&gt;. Remember to start xbindkeys at the start of you session (for example add it to &lt;code&gt;.gnomerc&lt;/code&gt; or even better to &lt;code&gt;.xprofile&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;To rearrange the mouse buttions how I like them, I use a Xmodmap file (/etc/X11/Xmodmap):&lt;/p&gt;
&lt;pre&gt;
!MX1000
pointer = 1 10 3 4 5 7 6 8 9 2 11 12 14 13
&lt;/pre&gt;
&lt;p&gt;This rearranges the second button (middle button on the scroll-wheel) to the thumb button, and reverses the tilt-buttons of the scroll-wheel. This could also be in &lt;code&gt;.xmodmaprc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;xev&lt;/code&gt; to find out which number any button has (works for the keyboard too).&lt;/p&gt;
&lt;h1&gt;Performance issues with Firefox&lt;/h1&gt;
&lt;p&gt;I noticed severe performance issues with Firefox each time I opened a Google Spreadsheet. The interesting thing was that Xorg took 100% of the &lt;span class="caps"&gt;CPU&lt;/span&gt;, not Firefox itself. I resolved the issue more or less accidently: I installed the binary &lt;a href="http://www.nvidia.com/object/unix.html"&gt;NVidia driver&lt;/a&gt; which gave the whole system a real performance boost.&lt;/p&gt;
&lt;h1&gt;Bootup Performance&lt;/h1&gt;
&lt;p&gt;The next thing I attacked was the boot-time. First I disabled many services I didn&amp;#8217;t use. Usually I create a folder called &lt;code&gt;disabled&lt;/code&gt; within the runlevel directories (/etc/rcS.d and /etc/rc2.d) and move the services I don&amp;#8217;t use (or don&amp;#8217;t know I use).&lt;/p&gt;
&lt;p&gt;Using a coll utility called &lt;a href="http://www.bootchart.org/"&gt;BootChart&lt;/a&gt; (stores it&amp;#8217;s charts in &lt;code&gt;/var/log/bootchart/&lt;/code&gt;) I found out that a big chunk of my startup time is taken by getting my IP by &lt;span class="caps"&gt;DHCP&lt;/span&gt;. I changed my configuration to a static IP, so I could reduce the startup time by 10 seconds.&lt;/p&gt;
&lt;p&gt;My chart currently shows a lot of time (and I/O access) is coming from &lt;code&gt;modprobe&lt;/code&gt;, I wonder if compiling the Kernel with all necessary drivers included into the Kernel would give me even less startup time&amp;#8230; Maybe I&amp;#8217;ll try that sometime too :-).&lt;/p&gt;
&lt;p&gt;So, now my Ubuntu setup seems quite nice, unfortunately I edited a lot of files in the process, which are easily lost so this is more or less a tutorial for my future-me to get the stuff working again.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/fM9Aa1da1y8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/linux.html</feedburner:origLink></entry>
 
 <entry>
   <title>Challenge Response Spam Filter</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/R6fA__aj4z0/challenge_response_spam_filter.html" />
   <updated>2007-08-11T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/reviews/challenge_response_spam_filter</id>
   <content type="html">&lt;p&gt;The &lt;a href="http://en.wikipedia.org/wiki/Challenge-response_spam_filtering"&gt;challenge-response spam-filter&lt;/a&gt; (&lt;a href="http://tools.ietf.org/html/rfc3834"&gt;RFC3834&lt;/a&gt;) troubles me lately. If you don&amp;#8217;t know it, here is how it works if both parties have a challenge-response spam-filter:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;I write an email to someone@domain&lt;/li&gt;
	&lt;li&gt;The address gets whitelisted on my machine&lt;/li&gt;
	&lt;li&gt;The receiver doesn&amp;#8217;t get my message&lt;/li&gt;
	&lt;li&gt;I get a message from the receivers mail-server to which I should reply&lt;/li&gt;
	&lt;li&gt;I reply to the automatic message&lt;/li&gt;
	&lt;li&gt;The receivers mail-server whitelists my address and delivers my initial mail&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So far so good. Three questions pop up:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;What if the spammer uses my whitelisted email address to send his spam?&lt;/li&gt;
	&lt;li&gt;What if only one of the two has a challenge-response spam-filter?&lt;/li&gt;
	&lt;li&gt;What if spammers start to automatically reply to those messages?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Concerning the faked email address: there are several methods to tackle this problem. One is to use &lt;a href="http://en.wikipedia.org/wiki/Sender_Policy_Framework"&gt;&lt;span class="caps"&gt;SPF&lt;/span&gt;&lt;/a&gt; (&lt;a href="http://tools.ietf.org/html/rfc4408"&gt;RFC4408&lt;/a&gt;) records for the domain (explicitly list allowed hosts), the other is to whitelist an email address together with the sending host. I&amp;#8217;m not sure whether this fully solves the problem&amp;#8230; .&lt;/p&gt;
&lt;p&gt;The second question is a bit more fuzzy. If Alice has a challenge-response spam-filter and Bob doesn&amp;#8217;t, then we have two scenarios: Alice sends Bob a mail, or Bob sends Alice a mail:&lt;/p&gt;
&lt;p&gt;A &amp;#8594; B:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Alice sends Bob the mail&lt;/li&gt;
	&lt;li&gt;Bob&amp;#8217;s address gets whitelisted&lt;/li&gt;
	&lt;li&gt;All mails are delivered&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Good, here it seems that we don&amp;#8217;t have a problem.&lt;/p&gt;
&lt;p&gt;B &amp;#8594; A (as happened to me):&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Bob sends Alice a mail&lt;/li&gt;
	&lt;li&gt;Alice&amp;#8217;s mail-server sends Bob a verification message&lt;/li&gt;
	&lt;li&gt;Bob&amp;#8217;s spam-filter filters the verification message because the company selling&lt;br /&gt;
  the spam-filter inserts advertising into the verification message&lt;/li&gt;
	&lt;li&gt;Bob never notices that the mail wasn&amp;#8217;t delivered&lt;/li&gt;
	&lt;li&gt;Alice has to check her spam-folder to see whether someone didn&amp;#8217;t receive the&lt;br /&gt;
  verification message (or ignored it)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#8217;m very sceptical whether the challenge-response spam-filter is worth the trouble, partly because my spam-filter (GMail) filtered the verification message of my buddy, and partly because it&amp;#8217;s very easy to automate the verification process. The argument of my buddy (who employs the challenge-response spam-filter) was that spammers use fake email addresses to send their mail and usually don&amp;#8217;t receive any replies (I think fake email addresses are used by malware, which sends it&amp;#8217;s junk using my address book &amp;#8594; remember: automatically whitelisted since I&amp;#8217;m likely to have had a conversation with these receivers before).&lt;/p&gt;
&lt;p&gt;Currently I&amp;#8217;m quite happy with automatic spam classification, they filter about 90 percent of my spam messages. The remaining messages are easily deleted by hand. A spam filter doesn&amp;#8217;t need to recognize 100 percent of the spam messages as long it filters enough to keep the &amp;#8220;mark as spam&amp;#8221; actions sparse. A spam-filter which generates false-positives is &lt;strong&gt;much&lt;/strong&gt; more troubling because one has to skim through (usually) thousands of spam messages and make sure there is no false-positive. Especially if you are a company relying on communication with customers, I wouldn&amp;#8217;t risk loosing a single one for the comfort of not having to delete a few messages a day.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/R6fA__aj4z0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/reviews/challenge_response_spam_filter.html</feedburner:origLink></entry>
 
 <entry>
   <title>Vim Introduction and Tutorial</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/qYAcdiq2IJk/vim_tutorial.html" />
   <updated>2007-02-23T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/tutorials/vim_tutorial</id>
   <content type="html">&lt;p&gt;I often tried to learn the great Emacs editor/&lt;span class="caps"&gt;IDE&lt;/span&gt;/operating system. The last time I tried it, I spent some time getting comfortable with it until I wanted to customize my &lt;code&gt;.emacs&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;That was the point when I entered &lt;code&gt;vi .emacs&lt;/code&gt;. As soon as I realized what I&amp;#8217;ve done, I knew that Vim has won me over a long time ago.&lt;/p&gt;
&lt;p&gt;So, here I am &amp;#8211; using Vim as my editor&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt; of choice.&lt;/p&gt;
&lt;p&gt;Another big motivational boost came after I discovered that my preferred shell (&lt;a href="http://www.zsh.org/"&gt;&lt;span class="caps"&gt;ZSH&lt;/span&gt;&lt;/a&gt;) has an awesome vi-mode including the command mode (yes, you can switch between command and insert mode!).&lt;/p&gt;
&lt;p&gt;Vim has a great deal of features, and learning them takes some time. Of course there are many online-tutorials and tips&amp;#8217;n&amp;#8217;tricks pages, but the &lt;a href="http://vimdoc.sourceforge.net/htmldoc/usr_toc.html"&gt;help-files&lt;/a&gt; are very good too! There are overview-pages, summary pages and some comments at the commands.&lt;/p&gt;
&lt;p&gt;I took the approach to start using some tutorial and let the help-system guide (type &lt;code&gt;:help &amp;lt;command&amp;gt;&lt;/code&gt; to get help for the command) me through the rest. I like to try the commands in a test-file, and take a short note of important commands.&lt;/p&gt;
&lt;p&gt;Another reason I like to use Vim is because it&amp;#8217;s much more healthy than Emacs (using the default-keymappings).  Healthy? Many commands are easily typed with a single keystroke &amp;#8211; the virtue of a modal editor, instead of long command-chains with lots of modifier keys.  Even if you have a natural keyboard, pressing Ctrl, Alt etc is certainly not natural at all.&lt;/p&gt;
&lt;p&gt;Just remember: Vim&amp;#8217;s basics are really very simple, but in combination the simple commands become very powerful.&lt;/p&gt;
&lt;h2&gt;Modes&lt;/h2&gt;
&lt;p&gt;You have &lt;strong&gt;3 modes&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Command mode: all keystrokes are interpreted as commands&lt;/li&gt;
	&lt;li&gt;Insert mode: most keystrokes are inserted as text (leaving out those with&lt;br /&gt;
  modifier keys)&lt;/li&gt;
	&lt;li&gt;Visual mode: helps to visually select some text, may be seen as a submode of&lt;br /&gt;
  the the command mode.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/modes.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;To switch from the insert or visual mode to the command mode, type &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To switch from the command mode to the insert mode type one of&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;i&lt;/code&gt;   &amp;#8230;switch to insert mode before the current position&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;a&lt;/code&gt;   &amp;#8230;switch to insert mode after the current position (append)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;I&lt;/code&gt;   &amp;#8230;jump to the first non-blank character in the current line and switch&lt;br /&gt;
  to the insert mode&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;A&lt;/code&gt;   &amp;#8230;jump to the last character of the current line and switch to the&lt;br /&gt;
  insert mode&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To switch from the command mode to the visual mode type one of&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;v&lt;/code&gt;   &amp;#8230;switch to the visual mode (character oriented)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;V&lt;/code&gt;   &amp;#8230;switch to the visual mode (line oriented)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Ctrl-v&lt;/code&gt; &amp;#8230;switch to the block-visual mode (select rectangles of text)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All commands that take a range (for example subtitution, delete, copy or indentation) work with the visual mode too.&lt;/p&gt;
&lt;h2&gt;Movement&lt;/h2&gt;
&lt;p&gt;The simplest movement commands are&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;h&lt;/code&gt;   &amp;#8230;move left&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;l&lt;/code&gt;   &amp;#8230;move right&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;k&lt;/code&gt;   &amp;#8230;move up&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;j&lt;/code&gt;   &amp;#8230;move down&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Obviously these commands work only in the command mode, of course you can also use the cursor keys (in all three modes).&lt;/p&gt;
&lt;p&gt;There are a lot of movement commands available in Vim, I&amp;#8217;ll only cover a few, but if you need something special very often take a look at the help, I&amp;#8217;m sure you&amp;#8217;ll find something usable.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/commands.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Vim distinguishes between screen-lines (those shown on the monitor) and real lines (those ended with a new-line).&lt;/p&gt;
&lt;p&gt;So here the most important commands&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;0&lt;/code&gt;   &amp;#8230;first column of the line&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;^&lt;/code&gt;   &amp;#8230;first non-blank character of the line&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;w&lt;/code&gt;   &amp;#8230;jump to next word&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;W&lt;/code&gt;   &amp;#8230;jump to next word, ignore punctuation&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;e&lt;/code&gt;   &amp;#8230;jump to word-end&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;E&lt;/code&gt;   &amp;#8230;jump to word-end, ignore punctuation&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;b&lt;/code&gt;   &amp;#8230;jump to word-beginning&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;B&lt;/code&gt;   &amp;#8230;jump to word-beginning, ignore punctuation&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;ge&lt;/code&gt;  &amp;#8230;jump to previous word-ending&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;gE&lt;/code&gt;  &amp;#8230;jump to previous word-ending, ignore punctuation&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;g_&lt;/code&gt;  &amp;#8230;jump to last non-blank character of the line&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;$&lt;/code&gt;   &amp;#8230;jump to the last character of the line&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you remember just a few of them, you&amp;#8217;ll get very quickly from A to B!  Another important fact is, that these commands give the range for other commands.&lt;/p&gt;
&lt;h2&gt;Editing&lt;/h2&gt;
&lt;p&gt;Inserting text is pretty simple in Vim, just type &lt;code&gt;i&lt;/code&gt; and start typing. But Vim offers quite sophisticated text-editing commands.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;d&lt;/code&gt;  &amp;#8230;delete the characters from the cursor position up the position given by the next command (for example &lt;code&gt;d$&lt;/code&gt; deletes all character from the current cursor position up to the last column of the line).&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;c&lt;/code&gt;  &amp;#8230;change the character from the cursor position up to the position indicated by the next command.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;x&lt;/code&gt;   &amp;#8230;delete the character under the cursor.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;X&lt;/code&gt;   &amp;#8230;delete the character before the cursor (Backspace).&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;y&lt;/code&gt;  &amp;#8230;copy the characters from the current cursor position up to the position indicated by the next command.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;p&lt;/code&gt;   &amp;#8230;paste previous deleted or yanked (copied) text after the current cursor position.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;P&lt;/code&gt;   &amp;#8230;paste previous deleted or yanked (copied) text before the current cursor position.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;r&lt;/code&gt;  &amp;#8230;replace the current character with the newly typed one.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;s&lt;/code&gt;  &amp;#8230;substitute the text from the current cursor position up to the position given by the next command with the newly typed one.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;.&lt;/code&gt;  &amp;#8230;repeat the last insertion or editing command (x,d,p&amp;#8230;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Doubling &lt;code&gt;d&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt; or &lt;code&gt;y&lt;/code&gt; operates on the whole line, for example &lt;code&gt;yy&lt;/code&gt; copies the whole line.&lt;/p&gt;
&lt;p&gt;Please note, many commands are much more powerful than I describe them here.  For example you can specify a buffer into some text is yanked. Typing &lt;code&gt;"ayy&lt;/code&gt; copies the current line into register &lt;code&gt;a&lt;/code&gt;, pasting the contents of register &lt;code&gt;a&lt;/code&gt; is done by &lt;code&gt;"ap&lt;/code&gt;. Vim remembers the last few yanks and deletions in automatic registers, to show the contents of the registers type &lt;code&gt;:registers&lt;/code&gt;, you can also use them to paste some older text.&lt;/p&gt;
&lt;h2&gt;Visual Block&lt;/h2&gt;
&lt;p&gt;Using the visual block-mode it&amp;#8217;s possible to insert characters on each line of the selection easily.&lt;/p&gt;
&lt;p&gt;Suppose you have selected a rectangle (using &lt;code&gt;Ctrl-v&lt;/code&gt;), you can insert text in front of it by typing &lt;code&gt;I&lt;/code&gt; (switch to insert mode) and inserting your text.  As soon as you leave the insert mode, the text will be added to all the other selected lines. Use &lt;code&gt;A&lt;/code&gt; to enter text &lt;strong&gt;after&lt;/strong&gt; the selection.&lt;/p&gt;
&lt;p&gt;Another useful feature is to substitute the whole block with a new text. For that matter select a block and type &lt;code&gt;s&lt;/code&gt;, Vim enters the insert mode and you can type. After you leave the insert mode, Vim inserts the text in the remaining lines.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;d like to append some text at the end of some lines, use &lt;code&gt;Ctrl-v$&lt;/code&gt; and select the lines. The difference between the former variant is, that the &lt;code&gt;$&lt;/code&gt; explicitly says &amp;#8220;end of line&amp;#8221; whereas a selection with &lt;code&gt;Ctrl-v&lt;/code&gt; operates on the columns, ignoring the text.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;Ctrl-v&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;
 This is a testNEWLY INSERTED
 This is a     NEWLY INSERTED
 This is       NEWLY INSERTED
&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;Ctrl-v$&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;
 This is a testNEWLY INSERTED
 This is aNEWLY INSERTED
 This isNEWLY INSERTED
&lt;/pre&gt;
&lt;h2&gt;Text-objects&lt;/h2&gt;
&lt;p&gt;Vim commands operate on &lt;strong&gt;text-objects&lt;/strong&gt; these are characters, words, characters delimited by parentheses, sentences and so on.&lt;/p&gt;
&lt;p&gt;For me the most important one is the &lt;strong&gt;inner word&lt;/strong&gt;: &lt;code&gt;iw&lt;/code&gt;. To select the current word, just type &lt;code&gt;viw&lt;/code&gt; (&lt;code&gt;v&lt;/code&gt; for selection mode, and &lt;code&gt;iw&lt;/code&gt; for the &lt;strong&gt;inner word&lt;/strong&gt;), similar for deletion: &lt;code&gt;diw&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The difference between inner-word/block and a-word/block etc is that the inner variant selects only the contents like the characters of the word (no blank afterwards) or the contents of the parentheses but not the parentheses. The a-variant selects the parentheses or a blank after a word too.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;iw&lt;/code&gt; &amp;#8230;inner word&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;aw&lt;/code&gt; &amp;#8230;a word&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;iW&lt;/code&gt; &amp;#8230;inner &lt;span class="caps"&gt;WORD&lt;/span&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;aW&lt;/code&gt; &amp;#8230;a &lt;span class="caps"&gt;WORD&lt;/span&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;is&lt;/code&gt; &amp;#8230;inner sentence&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;as&lt;/code&gt; &amp;#8230;a sentence&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;ip&lt;/code&gt; &amp;#8230;inner paragraph&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;ap&lt;/code&gt; &amp;#8230;a paragraph&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;i(&lt;/code&gt; or &lt;code&gt;i)&lt;/code&gt; &amp;#8230;inner block&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;a(&lt;/code&gt; or &lt;code&gt;a)&lt;/code&gt; &amp;#8230;a block&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;i&amp;lt;&lt;/code&gt; or &lt;code&gt;i&amp;gt;&lt;/code&gt; &amp;#8230;inner block&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;a&amp;lt;&lt;/code&gt; or &lt;code&gt;i&amp;gt;&lt;/code&gt; &amp;#8230;a block&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;i{&lt;/code&gt; or &lt;code&gt;i}&lt;/code&gt; &amp;#8230;inner block&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;a{&lt;/code&gt; or &lt;code&gt;a}&lt;/code&gt; &amp;#8230;a block&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;i"&lt;/code&gt; &amp;#8230;inner block&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;a"&lt;/code&gt; &amp;#8230;a block&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;i`&lt;/code&gt; &amp;#8230;inner block&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;a`&lt;/code&gt; &amp;#8230;a block&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here a quick visualisation of the commands the color and the &lt;span style="color: red"&gt;[ ]&lt;/span&gt; mark the selected text:&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Command &lt;/th&gt;
		&lt;th&gt;Text Object &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;iw&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; This is a &lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;test&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt; sentence. &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;aw&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; This is a &lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;test &lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt;sentence. &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;iW&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; This is a &lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;&amp;#8230;test&amp;#8230;&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt; sentence. &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;aW&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; This is a &lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;&amp;#8230;test&amp;#8230; &lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt;sentence. &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;is&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; &amp;#8230;sentence. &lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;This is a sentence.&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt; This&amp;#8230; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;as&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; &amp;#8230;sentence. &lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;This is a sentence. &lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt;This&amp;#8230; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;ip&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; End of previous paragraph.&lt;br/&gt;&lt;br/&gt;&lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;This is a paragraph. It has two sentences.&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;The next. &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;ap&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; End of previous paragraph.&lt;br/&gt;&lt;br/&gt;&lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;This is a paragraph. It has two sentences.&lt;br/&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt;The next. &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;i(&lt;/code&gt; or &lt;code&gt;i)&lt;/code&gt;   &lt;/td&gt;
		&lt;td&gt; 1 * (&lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;2 + 3&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt;) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;a(&lt;/code&gt; or &lt;code&gt;a)&lt;/code&gt;   &lt;/td&gt;
		&lt;td&gt; 1 * &lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;(2 + 3)&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;i&amp;lt;&lt;/code&gt; or &lt;code&gt;i&amp;gt;&lt;/code&gt;   &lt;/td&gt;
		&lt;td&gt; The &amp;lt;&lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;tag&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt;&amp;gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;a&amp;lt;&lt;/code&gt; or &lt;code&gt;i&amp;gt;&lt;/code&gt;   &lt;/td&gt;
		&lt;td&gt; The &lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;&amp;lt;tag&amp;gt;&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;i{&lt;/code&gt; or &lt;code&gt;i}&lt;/code&gt;   &lt;/td&gt;
		&lt;td&gt; some {&lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt; code block &lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt;} &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;a{&lt;/code&gt; or &lt;code&gt;a}&lt;/code&gt;   &lt;/td&gt;
		&lt;td&gt; some &lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;{ code block }&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;i"&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; The &amp;quot;&lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;best&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt;&amp;quot; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;a"&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; The&lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt; &amp;#8220;best&amp;#8221;&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;i`&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; The `&lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt;best&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt;` &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;a`&lt;/code&gt;           &lt;/td&gt;
		&lt;td&gt; The&lt;span style="color: red"&gt;[&lt;/span&gt;&lt;span style="background-color: yellow"&gt; `best`&lt;/span&gt;&lt;span style="color: red"&gt;]&lt;/span&gt; &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Try them out and remember the ones you need regularly (in my case &lt;code&gt;iw&lt;/code&gt; and &lt;code&gt;i(&lt;/code&gt;) they are the real time-savers!&lt;/p&gt;
&lt;h2&gt;Undo and Redo&lt;/h2&gt;
&lt;p&gt;Don&amp;#8217;t be afraid to try the various commands, you can undo almost anything using &lt;code&gt;u&lt;/code&gt; in the command mode &amp;#8211; even undo is undoable using &lt;code&gt;Ctrl-r&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Vim 7.0 introduced undo-branches, but I didn&amp;#8217;t have time to dig deeper.&lt;/p&gt;
&lt;h2&gt;External commands&lt;/h2&gt;
&lt;p&gt;In Vim it&amp;#8217;s easy to include the output of external commands or to filter the whole line or just a part through an external filter.&lt;/p&gt;
&lt;p&gt;To issue an external command type &lt;code&gt;:!command&lt;/code&gt;, the output will be shown and that&amp;#8217;s it.&lt;/p&gt;
&lt;p&gt;To filter the text through an external command type &lt;code&gt;:!sort %&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To insert the output of the external command in the current file type &lt;code&gt;:r!command&lt;/code&gt; (for example &lt;code&gt;:r!which ls&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Search for &amp;#8220;filter&amp;#8221; for more information &lt;code&gt;:h filter&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Searching and Replacing&lt;/h2&gt;
&lt;p&gt;Searching in Vim is very easy. Type &lt;code&gt;/&lt;/code&gt; in the command mode and insert the term you search, and Vim will search the file (in forward direction) for the term. Use &lt;code&gt;?&lt;/code&gt; for the backward direction. Using &lt;code&gt;n&lt;/code&gt; or &lt;code&gt;N&lt;/code&gt; you can repeat the search in the same or opposite direction.&lt;/p&gt;
&lt;p&gt;If the option &amp;#8220;incsearch&amp;#8221; is set, Vim immediately jumps to the matching text when you enter something. If &amp;#8220;hlsearch&amp;#8221; is set, it highlights all matches. To remove the highlight type &lt;code&gt;:nohl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Replacing something isn&amp;#8217;t very hard too, but you should have a good understanding of regular expressions.&lt;/p&gt;
&lt;p&gt;To substitute a regular expression with some other text, type &lt;code&gt;:%s/old/new/gc&lt;/code&gt; this command takes the whole file &lt;code&gt;%&lt;/code&gt;, and substitutes &lt;code&gt;s&lt;/code&gt; the word &amp;quot;old@ with &amp;#8220;new&amp;#8221; and looks for more than one occurrence within one line &lt;code&gt;g&lt;/code&gt; and asks if it really should replace the shown one &lt;code&gt;c&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To replace some text only in a selected area, select the area, and type &lt;code&gt;:s/old/new/g&lt;/code&gt;. This should look like &lt;code&gt;:'&amp;lt;,'&amp;gt;s/old/new/g&lt;/code&gt; in the command line.  You&amp;#8217;ll understand &lt;code&gt;'&amp;lt;&lt;/code&gt; and &lt;code&gt;'&amp;gt;&lt;/code&gt; after the &amp;#8220;Marks&amp;#8221; section.&lt;/p&gt;
&lt;h2&gt;Completion&lt;/h2&gt;
&lt;p&gt;While you are typing, it&amp;#8217;s pretty common to use the same word over and over again. Using &lt;code&gt;Ctrl-p&lt;/code&gt; Vim searches the currently typed text backwards for a word starting with the same characters as already typed. &lt;code&gt;Ctrl-x Ctrl-l&lt;/code&gt; completes the whole line.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re not sure how to type some word and you&amp;#8217;ve enabled spell-checking (&lt;code&gt;:set spell&lt;/code&gt;), you can type &lt;code&gt;Ctrl-x Ctrl-k&lt;/code&gt; to do a dictionary lookup for the already typed characters. Vim&amp;#8217;s completion system has much improved during the last major update (Vim 7.0).&lt;/p&gt;
&lt;p&gt;Note the completion commands work only in the &lt;strong&gt;insert mode&lt;/strong&gt;, they have other meanings in the command mode!&lt;/p&gt;
&lt;h2&gt;Marks&lt;/h2&gt;
&lt;p&gt;You can set marks within your documents to jump quickly between different positions of a document or even many documents.&lt;/p&gt;
&lt;p&gt;Vim automatically sets various marks like&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;{0-9}&lt;/code&gt; are the last 10 positions of closed files (0 the last, 1 the last but one)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;&amp;lt;&lt;/code&gt; and &lt;code&gt;&amp;gt;&lt;/code&gt; are the left and right position of marked texts&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;(&lt;/code&gt; and &lt;code&gt;)&lt;/code&gt; are the start or end of the current sentence&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;{&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt; are the start or end of the current paragraph&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;[&lt;/code&gt; and &lt;code&gt;]&lt;/code&gt; are the first or last character of the last yanked or changed text&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;.&lt;/code&gt;       position of the last change&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;'&lt;/code&gt; or  &lt;code&gt;`&lt;/code&gt; position before the last jump&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;"&lt;/code&gt;       position before the last exit of the file (local to a file)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;^&lt;/code&gt;       position of the last insert-stop&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To set a manual mark, use &lt;code&gt;m{a-zA-Z}&lt;/code&gt; (&lt;code&gt;m&lt;/code&gt; followed by either a,b..z or A,B,..Z), and to jump to one of the marks (manual or automatic) you can choose between &lt;code&gt;'&lt;/code&gt; and &lt;code&gt;`&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;'&lt;/code&gt; &amp;#8230;sets the cursor to the first non-blank character in the marked line&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;`&lt;/code&gt; &amp;#8230;sets the cursor to the exact position where the mark was set&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is a little difference between lower-case and upper-case characters:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;{a-z}&lt;/code&gt; are local to a file&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;{A-Z}&lt;/code&gt; are stored and available over sessions (associated with a file)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use &lt;code&gt;L&lt;/code&gt; for your work-log and &lt;code&gt;T&lt;/code&gt; for your time-table for example, and quickly update the information there.&lt;/p&gt;
&lt;p&gt;For example you can jump to the last known position of a file before it was closed by typing &lt;code&gt;`"&lt;/code&gt; (it&amp;#8217;s easy to configure Vim to do it automatically at start).&lt;/p&gt;
&lt;p&gt;To get a list of all marks Vim knows about type &lt;code&gt;:marks&lt;/code&gt;. To delete marks use &lt;code&gt;:delmarks&lt;/code&gt; (&lt;code&gt;:delmarks a b c&lt;/code&gt; removes marks &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt;, to delete all marks use &lt;code&gt;:delmarks!&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;Tabs, Buffers and Windows&lt;/h2&gt;
&lt;p&gt;Vim 7.0 has introduced tabs. We all know and love tabs, so it&amp;#8217;s not much to say here. (Just a note: tabs in Vim are a bit different than in other programs, you could also think of them as many Vim instances in a tabbed terminal window. The difference is, that each tab-page can have it&amp;#8217;s own layout. For example I could split my screen of the first tab, and view the same file in one window at the second tab&amp;#8230; . So Vim-tabs are a bit more powerful.)&lt;/p&gt;
&lt;p&gt;To open many files in tabs via the command line use &lt;code&gt;vim -p *.txt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To switch between tabs use the mouse (in gVim) or type &lt;code&gt;gt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To create a new empty tab type &lt;code&gt;:tabnew&lt;/code&gt;, or open a file in a new tab &lt;code&gt;:tabe xyz&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Buffers and Windows are a bit harder to understand. A window is what you see when you open Vim, when you open the help system (by typing &lt;code&gt;:help buffers&lt;/code&gt;), you&amp;#8217;ve got two windows. So they are no actual windows, but view-ports that Vim offers.&lt;/p&gt;
&lt;p&gt;You can open a window and split the current one horizontally using &lt;code&gt;:sp&lt;/code&gt; or vertically using &lt;code&gt;:vsp&lt;/code&gt;. This way Vim shows you the same &lt;strong&gt;buffer&lt;/strong&gt; in two different windows. You can open a new file too, using &lt;code&gt;:sp file&lt;/code&gt; or &lt;code&gt;:vsp file&lt;/code&gt;.  To switch between windows use the mouse or type &lt;code&gt;Ctrl-w {hjkl}&lt;/code&gt; in the command mode.&lt;/p&gt;
&lt;p&gt;A buffer is a file (most of the time), but isn&amp;#8217;t necessarily visible. So there are usually more buffers than windows. To show a different buffer in the current window, you can switch them using &lt;code&gt;:b NUMBER&lt;/code&gt;, where the buffer number can be looked up using &lt;code&gt;:buffers&lt;/code&gt;. In the standard configuration Vim forces you to save the currently shown buffer before it allows you to switch to another buffer, so don&amp;#8217;t be frustrated by it&amp;#8217;s complains. (Type &lt;code&gt;:set hidden&lt;/code&gt; to enable unsaved buffers, but be careful).&lt;/p&gt;
&lt;p&gt;Here my notes from the help-file:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;:b N&lt;/code&gt;      switch to buffer N&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;:buffers&lt;/code&gt;  show buffer list. Explanation:
	&lt;ul&gt;
		&lt;li&gt;&lt;code&gt;%&lt;/code&gt; current window&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;#&lt;/code&gt; alternate buffer (switch using &lt;code&gt;:e#&lt;/code&gt; or &lt;code&gt;:b#&lt;/code&gt;)&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;a&lt;/code&gt; active (loaded and visible)&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;h&lt;/code&gt; hidden (loaded but not visible)&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;+&lt;/code&gt; modified&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;:bd&lt;/code&gt;       unload the buffer and remove it from bufferlist (don&amp;#8217;t close Vim,&lt;br /&gt;
  even on the last buffer)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;:bun&lt;/code&gt;      unload the buffer but stay in bufferlist&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;:sp #N&lt;/code&gt;    split current window and edit buffer N&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;:w&lt;/code&gt;        write the current buffer to disk&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;:e file&lt;/code&gt;   load a file from disk&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;:q&lt;/code&gt;        closes current window (and Vim if it&amp;#8217;s the last one)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;:new&lt;/code&gt;      new empty window&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;:on&lt;/code&gt;       close all windows but the active one (&lt;code&gt;Ctrl-W o&lt;/code&gt;)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Ctrl-W {h,j,k,l}&lt;/code&gt; move between windows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Allow modified buffers to be hidden when the option &amp;#8216;hidden&amp;#8217; is set.  Buffers are automatically saved if the option &amp;#8216;hidden&amp;#8217; is not set, but &amp;#8216;autowrite&amp;#8217; is set.&lt;/p&gt;
&lt;h2&gt;Macros&lt;/h2&gt;
&lt;p&gt;Vim allows to replay some commands using &lt;code&gt;.&lt;/code&gt; (a dot). For more than one command use macros.&lt;/p&gt;
&lt;p&gt;You can start macro-recording using &lt;code&gt;q&lt;/code&gt; and one of {0-9a-zA-Z}, so for example &lt;code&gt;qq&lt;/code&gt; records the macro to buffer &amp;#8220;q&amp;#8221;. Hit &lt;code&gt;q&lt;/code&gt; when you are finished recording.&lt;/p&gt;
&lt;p&gt;Now you can replay the macro at any time using @q.&lt;/p&gt;
&lt;h2&gt;This is the end&lt;/h2&gt;
&lt;p&gt;I hope I could get you started for mastering one of the most sophisticated editors out there. The last thing I can do now is to include my configuration file. Use &lt;code&gt;:help ...&lt;/code&gt; to explore Vim&amp;#8217;s powers further and write a tutorial for the next apprentice.&lt;/p&gt;
&lt;p&gt;Place the &lt;a href="http://blog.interlinked.org/static/files/vimrc"&gt;vimrc&lt;/a&gt; into your home-directory (&lt;code&gt;~/.vimrc&lt;/code&gt;), but make sure you don&amp;#8217;t have one already.&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; Vim is an &lt;strong&gt;editor&lt;/strong&gt;, no &lt;span class="caps"&gt;IDE&lt;/span&gt; or operating system. Don&amp;#8217;t try to make an &lt;span class="caps"&gt;IDE&lt;/span&gt; out of it, if you like IDEs use one! Of course it&amp;#8217;s possible to automate many tasks, like compiling and jumping to errors reported by the compiler, for that matter look at Vim&amp;#8217;s plugins.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/qYAcdiq2IJk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/vim_tutorial.html</feedburner:origLink></entry>
 
 <entry>
   <title>Haskell - Laziness</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/uDSoCyQi_Rk/haskell_laziness.html" />
   <updated>2007-01-29T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/tutorials/haskell_laziness</id>
   <content type="html">&lt;p&gt;Haskell is a non-strict, or &lt;em&gt;lazy&lt;/em&gt;, language. This means it evaluates expressions only when it needs their results.&lt;/p&gt;
&lt;p&gt;Laziness is one of the things that make Haskell special &amp;#8211; really special. Lazy evaluation allows easy handling of &lt;em&gt;infinite&lt;/em&gt; data-structures.&lt;/p&gt;
&lt;p&gt;Lets look at a few infinite examples. The most simple one is the list of all integers&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[1..]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s it&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Another example &amp;#8211; containing all odd integers looks like&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[1,3..]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another way to define a list of all odd integers is&lt;/p&gt;
&lt;p&gt;&lt;code&gt;filter odd [1..]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This&lt;/strong&gt; is laziness at work. How is it possible to work with infinite lists? How can we filter an infinite list? The answer is simple: we do only what we have to do! The expression &lt;code&gt;filter odd [1..]&lt;/code&gt; doesn&amp;#8217;t do &lt;strong&gt;anything&lt;/strong&gt; but to tell the compiler &amp;#8220;&lt;em&gt;if we need a value from that list, this is &lt;strong&gt;how&lt;/strong&gt; it is computed&lt;/em&gt;&amp;#8221;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;print $ take 10 $ filter odd [1..]&lt;/code&gt; computes the first 10 numbers of the list, and prints it to stdout (try to omit &amp;#8220;take 10&amp;#8221; from the expression).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;$&lt;/code&gt; operator saves us from parentheses. The above example could easily be written as &lt;code&gt;print (take 10 (filter odd [1..]))&lt;/code&gt;. If you&amp;#8217;re not very sure about precedences stick with the parentheses, I tend to write my code using parentheses and rewrite it using &lt;code&gt;$&lt;/code&gt; afterwards.&lt;/p&gt;
&lt;h2&gt;Fibonacci&lt;/h2&gt;
&lt;p&gt;A popular example for infinite lists is the Fibonacci row, it is easily defined as&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    fib :: [Integer]
    fib = 1 : 2 : zipWith (+) fib (tail fib)
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;(zipWith takes two lists, and generates a new list by combining each pair of elements into a new one).&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/fibonacci.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The definition of the list is &lt;strong&gt;recursive&lt;/strong&gt;, another nice property of laziness &amp;#8211; you couldn&amp;#8217;t do that in a strict language! Please don&amp;#8217;t be confused by the illustration &amp;#8211; the three lists are the &lt;strong&gt;same&lt;/strong&gt; list!&lt;/p&gt;
&lt;p&gt;Obviously we wouldn&amp;#8217;t use that list for real work using Fibonacci numbers &amp;#8211; it would require too much memory&amp;#8230;&lt;/p&gt;
&lt;p&gt;If we&amp;#8217;d like to generate all Fibonacci number the above definition is the best we can do, &lt;strong&gt;but&lt;/strong&gt;, if we&amp;#8217;d like to get a specific Fibonacci number, we&amp;#8217;d rather take another definition:&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    fib :: Int -&amp;gt; Integer
    fib n = fibHlpr n 1 2
      where
        fibHlpr 0 a _ = a
        fibHlpr 1 _ b = b
        fibHlpr n a b = fibHlpr (n-1) b (a+b)
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;This is a &lt;a href="http://mitpress.mit.edu/sicp/full-text/sicp/book/node15.html"&gt;iterative process&lt;/a&gt;. Let&amp;#8217;s compare the profiling of the two methods to compute the 100000st Fibonacci number:&lt;/p&gt;
&lt;p&gt;Using the option &lt;code&gt;+RTS -hc&lt;/code&gt; for profiling generates a graph of the memory usage on the heap (see &lt;a href="http://www.haskell.org/ghc/docs/latest/html/users_guide/prof-heap.html"&gt;the documentation&lt;/a&gt;) this reveals that &lt;strong&gt;both&lt;/strong&gt; versions take about 600k of heap:&lt;/p&gt;
&lt;p&gt;Using lists:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/fib1.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Using the iterative process:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/fib2.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Another profiling option reveals statistics for the garbage-collector (parameter &lt;code&gt;-S&lt;/code&gt;):&lt;/p&gt;

Using the list:

&lt;pre&gt;
  &lt;code&gt;
604,159,196 bytes allocated in the heap
123,180,084 bytes copied during GC (scavenged)
 81,007,200 bytes copied during GC (not scavenged)
  4,234,128 bytes maximum residency (164 sample(s))

       1134 collections in generation 0 (  0.95s)
        164 collections in generation 1 (  0.57s)

         11 Mb total memory in use

  %GC time      50.1%  (48.6% elapsed)

  Alloc rate    399,083,404 bytes per MUT second

  Productivity  49.8% of total user, 47.1% of total elapsed
  &lt;/code&gt;
&lt;/pre&gt;

Using the iterative process:

&lt;pre&gt;
  &lt;code&gt;
602,528,044 bytes allocated in the heap
114,819,512 bytes copied during GC (scavenged)
 80,816,248 bytes copied during GC (not scavenged)
  4,017,816 bytes maximum residency (167 sample(s))

       1131 collections in generation 0 (  0.95s)
        167 collections in generation 1 (  0.58s)

         11 Mb total memory in use

  %GC time      50.2%  (48.6% elapsed)

  Alloc rate    397,003,108 bytes per MUT second

  Productivity  49.8% of total user, 47.0% of total elapsed
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;So, the new conclusion is, that both versions are nearly equivalent &amp;#8211; something I haven&amp;#8217;t seen coming.&lt;/p&gt;
&lt;p&gt;This is another example of &lt;strong&gt;premature optimization&lt;/strong&gt;, I thought that the infinite list is a problem, but obviously profiling proved me wrong, &lt;strong&gt;really&lt;/strong&gt; wrong!&lt;/p&gt;
&lt;p&gt;For computing specific Fibonacci numbers we should really use the formula shown &lt;a href="http://mitpress.mit.edu/sicp/full-text/sicp/book/node16.html"&gt;in &lt;span class="caps"&gt;SICP&lt;/span&gt;&lt;/a&gt;, but precision gets an issue using non-integrals&amp;#8230; .&lt;/p&gt;
&lt;h2&gt;Downside&lt;/h2&gt;
&lt;p&gt;Laziness has its downsides too, sometimes it requires quite a lot of memory. But, as I&amp;#8217;ve mentioned in the first article, Haskell is incredibly flexible and we can easily force strict evaluation &amp;#8211; look at &lt;a href="http://users.aber.ac.uk/afc/stricthaskell.html"&gt;this somewhat outdated article&lt;/a&gt; for examples, or at &lt;a href="http://www.haskell.org/haskellwiki/Performance/Strictness"&gt;this entry&lt;/a&gt; at the Haskell Wiki.&lt;/p&gt;
&lt;p&gt;Other performance tweaks can be found &lt;a href="http://www.haskell.org/haskellwiki/Performance"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;foldl, foldr, and foldl&amp;#8217;&lt;/h3&gt;
&lt;p&gt;Laziness&amp;#8217; problems are best illustrated using foldr, foldl, and fold&amp;#8217;.&lt;/p&gt;
&lt;p&gt;The fold operations &amp;#8220;fold&amp;#8221; a list to a single value, for example to generate the sum of a list, we could write:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;foldr (+) 0 [1,2,3,4]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Until now, nothing happened, but if we evaluate the statement, the following list is generated:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;code&gt;foldr (+) 0 [1,2,3,4]&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;1 + &lt;code&gt;foldr (+) 0 [2,3,4]&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;1 + (2 + &lt;code&gt;foldr (+) 0 [3,4]&lt;/code&gt;)&lt;/li&gt;
	&lt;li&gt;1 + (2 + (3 + &lt;code&gt;foldr (+) 0 [4]&lt;/code&gt;))&lt;/li&gt;
	&lt;li&gt;1 + (2 + (3 + (4 + &lt;code&gt;foldr (+) 0 []&lt;/code&gt;)))&lt;/li&gt;
	&lt;li&gt;1 + (2 + (3 + (4 + 0)))&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;1 + (2 + (3 + (4 + 0)))&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And &lt;strong&gt;after&lt;/strong&gt; that, all the additions are carried out.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;foldl&lt;/code&gt; works the other way around:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;foldl (+) 0 [1,2,3,4]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;generates&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;code&gt;foldl (+) 0 [1,2,3,4]&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;foldl (+) (0+1) [2,3,4]&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;foldl (+) ((0+1)+2) [3,4]&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;foldl (+) (((0+1)+2)+3) [4]&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;foldl (+) ((((0+1)+2)+3)+4) []&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;(((0 + 1) + 2) + 3) + 4&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Again, &lt;strong&gt;after&lt;/strong&gt; we build the list of additions we evaluate these, so the space requirement for foldr and foldl is O(n). That&amp;#8217;s where foldl&amp;#8217; comes in, it is a &lt;strong&gt;strict&lt;/strong&gt; version of foldl (it makes no sense to implement a strict version of foldr, try to figure out why).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;foldl' (+) 0 [1,2,3,4]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;generates no list of operations to carry out, but carries them out immediately. So The steps required by foldl&amp;#8217; are:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;code&gt;foldl' (+) 0 [1,2,3,4]&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;foldl' (+) 1 [2,3,4]&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;foldl' (+) 3 [3,4]&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;foldl' (+) 6 [4]&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;foldl' (+) 10 []&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;10&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Use &lt;code&gt;foldl'&lt;/code&gt; if you are sure that you have to carry out &lt;strong&gt;all&lt;/strong&gt; operations, for example for sums or products.&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; The notation &lt;code&gt;[a..b]&lt;/code&gt; generates the list of all integers between &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, obviously we can leave out the upper bound to generate infinite lists.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; There are some &lt;a href="http://programming.reddit.com/info/11oz3/comments"&gt;comments on Reddit&lt;/a&gt; explaining and clarifying some points. I &lt;strong&gt;had&lt;/strong&gt; to update the article because I simply screwed up with the first version. Thanks for all suggestions (now I wish my blog could handle comments too).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/uDSoCyQi_Rk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/haskell_laziness.html</feedburner:origLink></entry>
 
 <entry>
   <title>Haskell Basics</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/aKGY5pW9hVI/haskell_2.html" />
   <updated>2007-01-29T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/tutorials/haskell_2</id>
   <content type="html">&lt;p&gt;The article I wrote yesterday was just the beginning, today we&amp;#8217;ll look at the next step in becoming Haskell experts.&lt;/p&gt;
&lt;p&gt;Yesterday we&amp;#8217;ve learned how to split up our program and how to compile, or run it. Today we&amp;#8217;ll look at some basic features of Haskell.&lt;/p&gt;
&lt;h2&gt;Types&lt;/h2&gt;
&lt;p&gt;Haskell is strongly typed, meaning that the compiler knows the type of every object we have in our program. Yet we won&amp;#8217;t see types too often in Haskell because it uses &lt;strong&gt;type inference&lt;/strong&gt;, which means that the compiler deduces the type of your objects. We &lt;strong&gt;can&lt;/strong&gt; help it by providing type information, or include it to be sure that our objects have the specified type.&lt;/p&gt;
&lt;p&gt;Functions are often very generic and require not a specific type, but require that the type is the same at certain places. Let&amp;#8217;s look at the type of the &lt;code&gt;map&lt;/code&gt; function (we query the type via GHCi, the interactive shell of &lt;span class="caps"&gt;GHC&lt;/span&gt;, just start it with &lt;code&gt;ghci&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    Prelude&amp;gt; :t map 
    map :: (a -&amp;gt; b) -&amp;gt; [a] -&amp;gt; [b]
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;So, map has the type: &amp;#8220;first parameter is a function which takes type &amp;#8216;a&amp;#8217; and returns type &amp;#8216;b&amp;#8217;, the second parameter is a list of objects with type &amp;#8216;a&amp;#8217; and the returned object is of type list of objects of type &amp;#8216;b&amp;#8217;&amp;#8221;. So, map takes function and a list, and returns another list. &amp;#8216;a&amp;#8217; and &amp;#8216;b&amp;#8217; aren&amp;#8217;t further specified, and &lt;code&gt;map&lt;/code&gt; really doesn&amp;#8217;t care what is is.&lt;/p&gt;
&lt;p&gt;Look at this example:&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    map (\x -&amp;gt; x 40) [(+1), (*2), (/4)]
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;here the objects in the list are (partially applied) functions, and the function to map on the list is a &lt;strong&gt;lambda&lt;/strong&gt; (an anonymous function), which applies the given argument to 40.&lt;/p&gt;
&lt;p&gt;If we run the above code (again in ghci), we get:&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    Prelude&amp;gt; map (\x -&amp;gt; x 40) [(+1), (*2), (/4)]
    [41.0,80.0,10.0]
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Please note, that a list is always composed of objects of &lt;strong&gt;the same type&lt;/strong&gt;, so in this case it&amp;#8217;s the most general one. We can&amp;#8217;t mix integers and characters in a list, &lt;em&gt;but&lt;/em&gt; we can use tuples: &lt;code&gt;[(42,'a'), (45,'b')]&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Lambdas&lt;/h2&gt;
&lt;p&gt;The previous example used a lambda function, this is nothing special, just a function without a name. We use it if we define some small function which isn&amp;#8217;t used more than once.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s define a lambda which takes two integers and returns the product of the two:&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    \x y -&amp;gt; x*y
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;We could also give it a name:&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    product = \x y -&amp;gt; x*y
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;but then we would write it like&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    product x y = x*y
  &lt;/code&gt;
&lt;/pre&gt;
&lt;h2&gt;Partially applied functions&lt;/h2&gt;
&lt;p&gt;This is where I felt the urge to learn Haskell: we can partially apply a function! We&amp;#8217;ve already seen it above (for example &lt;code&gt;*2&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s define a function to increment an integer, &lt;code&gt;inc&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    inc1 a = a + 1
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;we could also write the above function as&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    inc2 = (+1)
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;The difference is the type, &lt;code&gt;inc1&lt;/code&gt; returns an integer, whereas &lt;code&gt;inc2&lt;/code&gt; returns &lt;strong&gt;a function&lt;/strong&gt;! Of course both act the same, but there is a difference.&lt;/p&gt;
&lt;p&gt;Lets look at another example:&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    map (+) [1,2,4,5]
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;this returns a list of partially applied functions! It returns &lt;code&gt;[(+1), (+2), (+4), (+5)]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One last example, &lt;code&gt;filter&lt;/code&gt; can be used to, well, filter some list. Lets filter out all number larger than 4:&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    filter (&amp;lt;=4) [1,2,3,4,5,6]
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Again &amp;#8211; we used a partially applied function! We can do quite a lot of amazing things with such easy and powerful abstractions, and that&amp;#8217;s the reason why Haskell is known for it&amp;#8217;s &lt;em&gt;glue&lt;/em&gt; capabilities.&lt;/p&gt;
&lt;h2&gt;Combining functions&lt;/h2&gt;
&lt;p&gt;The last concept I&amp;#8217;d like to show today is the combination operator: (&lt;strong&gt;.&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;Using this operator, we create a new function which takes the arguments of the first, and returns the return-value of the second.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;(f.g)(x)&lt;/code&gt; is the same as &lt;code&gt;f(g(x))&lt;/code&gt;. So, why is this important? Well, as I&amp;#8217;ve said in my previous post, Haskell is full of syntactic sugar, so using the combination operator we save some keystrokes.&lt;/p&gt;
&lt;p&gt;Here a simple example which extends the previous filter example to include only those numbers whose double is smaller than 5 (smaller or equal to 4).&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    filter ((&amp;lt;=4).(*2)) [1,2,3,4,5,6]
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Another way would be to use a simple lambda function:&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    filter (\x -&amp;gt; (2*x) &amp;lt;= 4) [1,2,3,4,5,6]
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;The combination operator makes code immensely readable, no useless arguments and parentheses which clutter up our programs, just plain functionality.&lt;/p&gt;
&lt;p&gt;Look at this imitation of the &lt;code&gt;rev&lt;/code&gt; command in Unix (taken from &lt;a href="http://cgi.cse.unsw.edu.au/~dons/blog/2006/12/17"&gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    main = interact (unlines . map reverse . lines)
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;could it get any simpler?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/aKGY5pW9hVI" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/haskell_2.html</feedburner:origLink></entry>
 
 <entry>
   <title>Haskell</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/qGSLqlVKyw0/haskell_introduction.html" />
   <updated>2007-01-28T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/tutorials/haskell_introduction</id>
   <content type="html">&lt;p&gt;Danger! If you are happy with your current knowledge of programming languages, don&amp;#8217;t read on &amp;#8211; Haskell might be responsible for &lt;a href="http://lukeplant.me.uk/blog.php?id=1107301645"&gt;some serious defects in your motivation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I was always some kind of programming language geek. I loved learning and playing around with all kinds of programming languages&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Currently I&amp;#8217;m trying to learn Haskell. Even though I learned functional programming at my university (two semesters using Haskell), I didn&amp;#8217;t really learn how to interact with the outside world. This is where things start to get messy, no matter how beautiful the language is.&lt;/p&gt;
&lt;p&gt;Haskell has many good ideas and takes programming to the next step. Things like implicit concurrency, explicit concurrency, purely functional, laziness, polymorphism, and various evaluation schemes provide many ways to get our job done (I wish I could show you &lt;strong&gt;how&lt;/strong&gt; to do that, in the meantime look at the tutorials at the end of the article or the &lt;a href="http://haskell.org/haskellwiki/Introduction"&gt;Haskell Wiki&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For me, Haskell was one of the harder languages to learn. The pure functional core is easy to understand, but the crossover from the outside world is not as easy.&lt;/p&gt;
&lt;p&gt;The reason, I think, is that Haskell provides quite a lot of syntactic sugar&lt;sup class="footnote" id="fnr3"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt; and it is incredible flexible. Another reason is that Monads &lt;strong&gt;seem&lt;/strong&gt; to be quite hard to understand, and Haskell is an ancient word meaning &amp;#8220;programming in monads&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Haskell tries to encapsulate the dirty world in a special Monad&lt;sup class="footnote" id="fnr2"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;, a show-stopper for many Haskell beginners (I&amp;#8217;ve included some &lt;strong&gt;good&lt;/strong&gt; tutorials on Monads at the end of this article to get you started).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Reading&lt;/em&gt; a Haskell program is a lot easier than writing one. The error messages from the compilers are very different, and due to type inference often hard to understand. It might be that someone who didn&amp;#8217;t spent his last 15 years programming in an imperative paradigm is better suited.&lt;/p&gt;
&lt;p&gt;Anyway, after you understand Haskell, your programs are much smaller and more clean than in any other language. Haskell is very expressive, and you tend to think more about your problem than how to formulate it in you language.&lt;/p&gt;
&lt;p&gt;Currently my only concern is &lt;em&gt;memory efficiency&lt;/em&gt; &amp;#8211; looking at &lt;a href="http://shootout.alioth.debian.org/"&gt;the great programming languages shootout&lt;/a&gt; Haskell is quite good, &lt;strong&gt;but&lt;/strong&gt; in my current understanding it&amp;#8217;s not straight forward to write memory efficient programs in Haskell. Anyway, we &lt;strong&gt;have&lt;/strong&gt; the options and the possibility to improve since we won&amp;#8217;t produce much code! Of course there are cases, where &lt;a href="http://haskell.org/haskellwiki/Introduction#When_C_is_better"&gt;Haskell is not the first choice&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Startup&lt;/h2&gt;
&lt;p&gt;Currently I can&amp;#8217;t teach anyone anything about Haskell programming &amp;#8211; I&amp;#8217;m still learning, but I can help you to get started.&lt;/p&gt;
&lt;h3&gt;Organization&lt;/h3&gt;
&lt;p&gt;When we start a Haskell program, the &lt;code&gt;main&lt;/code&gt; function of the &lt;code&gt;Main&lt;/code&gt; module gets called, so our entry-point (lets call it main.hs) should look like&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    module Main
    where

     main = do
       ...
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Larger programs should be split into modules, just like Java&amp;#8217;s package system, Haskell modules are hierarchic. For example if we&amp;#8217;ve got a module &lt;code&gt;Interlinked.Demo&lt;/code&gt;, we&amp;#8217;ll put it into the directory &lt;code&gt;Interlinked&lt;/code&gt; and call the file &lt;code&gt;Demo.hs&lt;/code&gt;. (This is not required for the &lt;code&gt;Main&lt;/code&gt; module!!)&lt;/p&gt;
&lt;p&gt;Demo.hs would look like:&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    module Interlinked.Demo
    where

      callMe = 10
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;to include the module in another module, we&amp;#8217;ll have to import it:&lt;/p&gt;
&lt;pre&gt;
  &lt;code&gt;
    module Main
    where

     import Interlinked.Demo

     main = do
       putStrLn $ show callMe
  &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;this imports all functions from the Demo.hs into the current namespace. If we have a name-clash (two functions with the same name), we have several possibilities to remedy the problem:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;hide the unused function &lt;code&gt;import Interlinked.Demo hiding (callMe)&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Qualify all calls &lt;code&gt;Interlinked.Demo.callMe&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Qualify only one package &lt;code&gt;import qualified Interlinked.Demo as D&lt;/code&gt;, and call it &lt;code&gt;D.callMe&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Compiling and Running&lt;/h3&gt;
&lt;p&gt;To run the program I&amp;#8217;d recommend using &lt;code&gt;runhaskell&lt;/code&gt; for development and compiling it to native code for the distribution or profiling.&lt;/p&gt;
&lt;p&gt;To run our program we simply type &lt;code&gt;runhaskell main.hs&lt;/code&gt; (if our Main module is in main.hs), or we can compile the code into a single executable using ghc: &lt;code&gt;ghc --make main.hs&lt;/code&gt;, the &lt;code&gt;--make&lt;/code&gt; option compiles all dependencies (if needed) and links everything.&lt;/p&gt;
&lt;p&gt;To sum it up:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;runhaskell main.hs&lt;/code&gt; for development&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;ghc --make main.hs&lt;/code&gt; for distribution and profiling&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We could also fire up a interactive shell and evaluate the methods selectively using &lt;code&gt;ghci main.hs&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Profiling&lt;/h3&gt;
&lt;p&gt;Profiling is quite important, especially in Haskell because it&amp;#8217;s easy to make some stupid mistakes. To profile our program we have to compile it using &lt;code&gt;ghc -prof -auto-all --make main.hs&lt;/code&gt;, this adds profiling code to our program (our code isn&amp;#8217;t recompiled if we didn&amp;#8217;t change our files, so we may need to delete old object files by ourselves).&lt;/p&gt;
&lt;p&gt;To run our program with profiling enabled, we start it with &lt;code&gt;./main +RTS -p&lt;/code&gt;. This generates a file (&lt;code&gt;main.prof&lt;/code&gt;) containing the profiling results.&lt;/p&gt;
&lt;p&gt;See the &lt;a href="http://www.haskell.org/ghc/docs/latest/html/users_guide/profiling.html"&gt;profiling documentation&lt;/a&gt; for more information on profiling.&lt;/p&gt;
&lt;h2&gt;Glasgow Haskell Compiler&lt;/h2&gt;
&lt;p&gt;The &lt;a href="http://www.haskell.org/ghc/"&gt;Glasgow Haskell Compiler&lt;/a&gt; is one of the better known Haskell compilers, Haskell itself is just a specification and there are many implementations (like &lt;a href="http://www.haskell.org/hugs/"&gt;Hugs&lt;/a&gt; and the &lt;a href="http://www.haskell.org/haskellwiki/Yhc"&gt;York Haskell Compiler&lt;/a&gt;). All of them implement Haskell 98, but in the meantime many extensions have been proposed and are available in some of the compilers (most of them in &lt;span class="caps"&gt;GHC&lt;/span&gt;).&lt;/p&gt;
&lt;h2&gt;More on Haskell&lt;/h2&gt;
&lt;p&gt;Since I didn&amp;#8217;t tell you how to &lt;em&gt;program&lt;/em&gt; in Haskell, I should point out some interesting tutorials:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.defmacro.org/ramblings/haskell-productivity.html"&gt;On Haskell, Intuition and Expressive Power&lt;/a&gt;, a love-letter for Haskell.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.scienceblogs.com/goodmath/2006/11/why_haskell.php"&gt;Why Haskell&lt;/a&gt; another love-letter for Haskell.&lt;/li&gt;
	&lt;li&gt;Haskell Hacking is a multi-part tutorial showing some amazing tricks. Nevertheless, it is aimed at the beginner: &lt;a href="http://cgi.cse.unsw.edu.au/~dons/blog/2006/12/16"&gt;Part 1&lt;/a&gt;, &lt;a href="http://cgi.cse.unsw.edu.au/~dons/blog/2006/12/17"&gt;Part 2&lt;/a&gt;, &lt;a href="http://cgi.cse.unsw.edu.au/~dons/blog/2006/12/18"&gt;Part 3&lt;/a&gt;, and &lt;a href="http://cgi.cse.unsw.edu.au/~dons/blog/2006/12/20"&gt;Part 4&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;It is quite popular to implement Lisp (and Scheme) in Haskell: &lt;a href="http://halogen.note.amherst.edu/~jdtang/scheme_in_48/tutorial/overview.html"&gt;Write Yourself a Scheme in 48 hours&lt;/a&gt; and &lt;a href="http://www.defmacro.org/ramblings/lisp-in-haskell.html"&gt;Writing a Lisp Interpreter in Haskell&lt;/a&gt;.&lt;/li&gt;
	&lt;li&gt;Hal Daumé &lt;span class="caps"&gt;III&lt;/span&gt; has written a very good introduction into Haskell: &lt;a href="http://www.cs.utah.edu/~hal/docs/daume02yaht.pdf"&gt;Yet Another Haskell Tutorial&lt;/a&gt; maybe the &lt;a href="http://diveintopython.org/"&gt;Dive Into Python&lt;/a&gt; for Haskell.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;span class="caps"&gt;API&lt;/span&gt; of Haskell is available at &lt;a href="http://www.haskell.org/ghc/docs/latest/html/libraries/index.html"&gt;Haskell Hierarchical Libraries&lt;/a&gt; and on &lt;a href="http://www.zvon.org/other/haskell/Outputglobal/index.html"&gt;Zvon&lt;/a&gt;. There is also a nice (very nice!) search engine for the &lt;span class="caps"&gt;API&lt;/span&gt;: &lt;a href="http://haskell.org/hoogle/"&gt;Hoogle&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Monads&lt;/h3&gt;
&lt;p&gt;The first two of the following tutorials give an easy to understand introduction (and a good metaphor) to Monads, and the third one (All about Monads) is the most complete one with quite a lot of background:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://en.wikibooks.org/wiki/Programming:Haskell_monads"&gt;Understanding monads&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.alpheccar.org/en/posts/show/60"&gt;A newbie in Haskell land or another monad tutorial&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.nomaware.com/monads/"&gt;All about Monads&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other sources include the &lt;a href="http://www.haskell.org/haskellwiki/Haskell"&gt;Haskell homepage&lt;/a&gt; and of course Google. If you like books more than online tutorials, check out &lt;a href="http://www.amazon.de/gp/product/0521644089/httwwwintxorg-21/"&gt;The Haskell School of Expression&lt;/a&gt;, but it&amp;#8217;s not meant for the beginner. The Haskell book for beginners seems to be &lt;a href="http://www.amazon.de/gp/product/0201342758/httwwwintxorg-21/"&gt;Haskell. The Craft of Functional Programming&lt;/a&gt;. Recently (January 2007) a new book &lt;a href="http://www.amazon.de/gp/product/0521692695/httwwwintxorg-21/"&gt;Programming in Haskell&lt;/a&gt; came up, this one is also targeted at the beginner.&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; To date I&amp;#8217;ve at least written a (more or less) simple program in Assembler, Bash, C, C++, C#, Cobol, &lt;span class="caps"&gt;GWA&lt;/span&gt; Basic, Haskell, Java, JavaScript, Lisp, Mosel, Pascal, PL/I, Prolog, Python, Ruby, Smalltalk, XQuery, &lt;span class="caps"&gt;XSLT&lt;/span&gt;, and various presentation languages like LaTeX and &lt;span class="caps"&gt;HTML&lt;/span&gt;, but there are &lt;a href="http://en.wikipedia.org/wiki/Alphabetical_list_of_programming_languages"&gt;so much more to learn&lt;/a&gt;. I can&amp;#8217;t remember most of them, but as far as I can remember is Smalltalk the one I had most fun with. Probably Assembler ranges very high in the fun-scale too &amp;#8211; I used to write little &lt;a href="http://en.wikipedia.org/wiki/Terminate_and_Stay_Resident"&gt;&lt;span class="caps"&gt;TSR&lt;/span&gt; programs&lt;/a&gt; and install them on my schools computers&amp;#8230; no harm done. Pascal and C were the languages I learned programming with, but &lt;span class="caps"&gt;GWA&lt;/span&gt; Basic was the very first language I used (on my Atari 2600 ST) :-).&lt;/p&gt;
&lt;p class="footnote" id="fn2"&gt;&lt;a href="#fnr2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; Monads are used for a lot more than interacting with the world!&lt;/p&gt;
&lt;p class="footnote" id="fn3"&gt;&lt;a href="#fnr3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; It&amp;#8217;s certainly no syntactic minimalist like Lisp.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I just found &lt;a href="http://blogs.nubgames.com/code/?p=17"&gt;an interesting article&lt;/a&gt; with quite the same experiences like I had. Anyway, it&amp;#8217;s good to see that it&amp;#8217;s not completely my fault.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/qGSLqlVKyw0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/haskell_introduction.html</feedburner:origLink></entry>
 
 <entry>
   <title>MacFUSE</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/w2Me5ej1a7E/macfuse.html" />
   <updated>2007-01-24T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/reviews/macfuse</id>
   <content type="html">&lt;p&gt;You probably heard about &lt;a href="http://code.google.com/p/macfuse/"&gt;MacFUSE&lt;/a&gt; (&lt;a href="http://googlemac.blogspot.com/2007/01/taming-mac-os-x-file-systems.html"&gt;announcement&lt;/a&gt;). MacFUSE is an OS X implementation of the popular &lt;a href="http://fuse.sourceforge.net/"&gt;&lt;span class="caps"&gt;FUSE&lt;/span&gt;&lt;/a&gt; project (well known to Linux enthusiasts).&lt;/p&gt;
&lt;p&gt;I just found a tech-demo video showing some really interesting features and possibilities of &lt;span class="caps"&gt;FUSE&lt;/span&gt; (of course it&amp;#8217;s not limited to MacFUSE).&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;SSHFS&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;The most popular filesystem is the &lt;a href="http://fuse.sourceforge.net/sshfs.html"&gt;&lt;span class="caps"&gt;SSHFS&lt;/span&gt;&lt;/a&gt;, it allows you to mount directories of remote computers via &lt;span class="caps"&gt;SSH&lt;/span&gt;. No more Samba or network sharing hassles, just login with your usual &lt;span class="caps"&gt;SSH&lt;/span&gt;-account and you&amp;#8217;re done. Surely this is a great tool for people constantly working remote, but for the others?&lt;/p&gt;
&lt;h2&gt;SpotlightFS&lt;/h2&gt;
&lt;p&gt;Today Google announced (did I mention that MacFUSE comes from Google engineers?) &lt;a href="http://googlemac.blogspot.com/2007/01/spotlight-file-system-for-macfuse.html"&gt;SpotlightFS&lt;/a&gt;, which is also great, but again not very interesting for most people. You get real filesystem access to stored searches, instead of a special filetype containing your search.&lt;/p&gt;
&lt;h2&gt;What really kicks ass&lt;/h2&gt;
&lt;p&gt;Somewhere within the &lt;a href="http://code.google.com/p/macfuse/w/list"&gt;MacFUSE wiki&lt;/a&gt; was a link to a tech-demo of MacFUSE. It shows some great ideas of what can (and should) be done using this technology.&lt;/p&gt;
&lt;p&gt;For example the &lt;strong&gt;PicasawebFS&lt;/strong&gt; was a real eye-opener! Easy upload, download and organization of pictures and albums via &lt;em&gt;your filesystem&lt;/em&gt; and &lt;strong&gt;live&lt;/strong&gt; on &lt;a href="http://picasaweb.google.com"&gt;Picasaweb&lt;/a&gt; (or Flickr).&lt;/p&gt;
&lt;p&gt;Imagine your blog as filesystem &amp;#8211; edit your entries with your &lt;em&gt;favorite editor&lt;/em&gt; in Textile, Markdown, or whatever suits you!&lt;/p&gt;
&lt;p&gt;The other (equally interesting) tech-demo filesystems are:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;DocFS &amp;#8211; another cool demo: it allows you to organize the documents written on &lt;a href="http://docs.google.com/"&gt;Google Docs &amp;amp; Spreadsheets&lt;/a&gt; and open them locally (live Word-export). Check at least this one out!&lt;/li&gt;
	&lt;li&gt;ProcFS &amp;#8211; a live view of the processes running on your computer (like &lt;code&gt;/proc&lt;/code&gt; on Linux).&lt;/li&gt;
	&lt;li&gt;&lt;span class="caps"&gt;RSSFS&lt;/span&gt; &amp;#8211; a filesystem view of a &lt;span class="caps"&gt;RSS&lt;/span&gt; feed, each entry is a link directly to the article.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href="http://video.google.com/videoplay?docid=3138515991250095768"&gt;Macworld 2007 MacFUSE Tech-Demo&lt;/a&gt; for more.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/w2Me5ej1a7E" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/reviews/macfuse.html</feedburner:origLink></entry>
 
 <entry>
   <title>Weblog Hoster/Software Comparison</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/HUOQOTbxa3E/weblogmatrix.html" />
   <updated>2007-01-23T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/misc/weblogmatrix</id>
   <content type="html">&lt;p&gt;Choosing the right tool for a job is very important, but often it is very tedious and bothersome to collect all the data you need.&lt;/p&gt;
&lt;p&gt;Once I was searching for a replacement of my previous Blog-hoster and ended up with &lt;a href="http://www.hobix.com/"&gt;Hobix&lt;/a&gt; (see &lt;a href="http://blog.interlinked.org/reviews/hobix.html"&gt;here&lt;/a&gt;). Hobix is certainly not for everyone &amp;#8211; and most likely not for me, but currently I&amp;#8217;m stuck with it.&lt;/p&gt;
&lt;p&gt;Anyways, if &lt;strong&gt;you&lt;/strong&gt; are searching for a good Blog-software, or Blog-hoster check out &lt;a href="http://www.weblogmatrix.org/"&gt;WeblogMatrix.com&lt;/a&gt;, a fresh Matrix-Wiki from the makers of &lt;a href="http://www.wikimatrix.org/"&gt;WikiMatrix.com&lt;/a&gt; and &lt;a href="http://www.forummatrix.org/"&gt;ForumMatrix.com&lt;/a&gt;. Maybe you can also add your own favorite system?&lt;/p&gt;
&lt;p&gt;Via &lt;a href="http://www.splitbrain.org/blog/2007-01/23-blog_software_comparison"&gt;it&amp;#8217;s developer&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/HUOQOTbxa3E" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/misc/weblogmatrix.html</feedburner:origLink></entry>
 
 <entry>
   <title>Blue on red</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/-963ggfH9pE/blue_on_red.html" />
   <updated>2006-11-20T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/misc/blue_on_red</id>
   <content type="html">&lt;p&gt;&lt;a href="http://del.icio.us"&gt;Del.icio.us&lt;/a&gt; is an amazing service&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;, clean, fast, and usable &amp;#8211; except for one thing, it&amp;#8217;s color scheme.&lt;/p&gt;
&lt;p&gt;A page which is bookmarked more often gets a darker background than other pages. Of course it&amp;#8217;s a nice feature, but the problem is that the background is &lt;strong&gt;red&lt;/strong&gt; and the font-color is &lt;strong&gt;light blue&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Some examples: &lt;img src="http://blog.interlinked.org/static/images/del_9179.png" alt="" /&gt; &lt;img src="http://blog.interlinked.org/static/images/del_16957.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Red and blue are on both ends of the color spectrum, which makes it hard or even impossible for humans to focus on both colors simultaneously.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/the_eye.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Additionally, blue light has to be much stronger than red light because humans have way less blue receptors then red and green.&lt;/p&gt;
&lt;p&gt;So, here a is little &lt;a href="http://blog.interlinked.org/static/files/deliciouscolorer.user.js"&gt;Greasemonkey script to improve the colors&lt;/a&gt;, the result looks like this: &lt;img src="http://blog.interlinked.org/static/images/del_16957_2.png" alt="" /&gt;.&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; Even when I&amp;#8217;m not posting my bookmarks to it, I still like to browse the &lt;a href="http://del.icio.us/popular/"&gt;popular pages&lt;/a&gt; or my old network.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/-963ggfH9pE" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/misc/blue_on_red.html</feedburner:origLink></entry>
 
 <entry>
   <title>How to read a paper</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/Q9LpFi8Kd8U/reading_papers.html" />
   <updated>2006-11-19T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/science/reading_papers</id>
   <content type="html">&lt;p&gt;Since I&amp;#8217;m writing my master&amp;#8217;s thesis, I have to read some scientific papers. In my previous years it wasn&amp;#8217;t necessary to read those, so I&amp;#8217;m not used to it. That&amp;#8217;s a pity because they contain bleeding edge knowledge compressed in a self-contained form of a few pages.&lt;/p&gt;
&lt;p&gt;I started reading them like technical books which didn&amp;#8217;t work because the contents of books are usually well edited (by people who are concerned about the language, not the content) and comparatively easy to read. Reading a paper is quite different, they are very compact and have nearly no redundancy which makes them hard to read.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve collected a few tips on how to read papers:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Read only one paper at a time. Papers differ in their notation and sometimes in their definitions (even papers from the same authors). Switching between papers (and notations as well as definitions) confuses and doesn&amp;#8217;t help you to get the knowledge you need.&lt;/li&gt;
	&lt;li&gt;Don&amp;#8217;t start in the middle of the paper. As said before, papers are highly compressed and have low redundancy, if you start in the middle you&amp;#8217;ll miss the explanations about their notation and the definitions. Scientists usually make their papers self-contained, so they include everything you&amp;#8217;ll need to know to understand the paper, use the information!&lt;/li&gt;
	&lt;li&gt;Read the whole paper before you start using the knowledge unless you&amp;#8217;re absolutely sure that you don&amp;#8217;t need the remaining chapters. But read the conclusion at the end of the paper, usually it contains an informal summary and open issues which may be of interest.&lt;/li&gt;
	&lt;li&gt;It&amp;#8217;s a good to do a simple real-world example while reading a paper. It&amp;#8217;s a method to slow you down and force you to understand every sentence of the paper.&lt;/li&gt;
	&lt;li&gt;Sometimes it takes hours only for a few pages of a paper, that&amp;#8217;s not unusual, even for those who worked for years in the field.&lt;/li&gt;
	&lt;li&gt;Don&amp;#8217;t get frustrated if you don&amp;#8217;t understand some paragraph, read the rest of the chapter, maybe there are further explanations on the topic, or just get some sleep and let your sub-consciousness work out the details.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: &lt;a href="http://www.ull.at/~djmaecki"&gt;Thomas Krennwallner&lt;/a&gt; pointed me to a guide called &lt;a href="http://www.cs.columbia.edu/~hgs/netbib/efficientReading.pdf"&gt;Efficient Reading of Papers in Science and Technology&lt;/a&gt;, it was written in 1989, but updated in 2000. Thanks, dude!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/Q9LpFi8Kd8U" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/science/reading_papers.html</feedburner:origLink></entry>
 
 <entry>
   <title>Brand new MacBook Pro</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/DJP-y1Ph9xM/macbook.html" />
   <updated>2006-11-08T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/reviews/macbook</id>
   <content type="html">&lt;p&gt;Today I&amp;#8217;ve got my brand new MacBook Pro, so I thought I share some observations for those who are tempted to buy one too.&lt;/p&gt;
&lt;p&gt;(&lt;a href="http://axel.blogr.com/videos/49928/main"&gt;It seems that I&amp;#8217;m not the only one who got a new &lt;span class="caps"&gt;MBP&lt;/span&gt; today&lt;/a&gt;. Have fun, &lt;a href="http://www.matsblog.com/"&gt;Mat&lt;/a&gt;.)&lt;/p&gt;
&lt;h2&gt;Size&lt;/h2&gt;
&lt;p&gt;First of all I&amp;#8217;m impressed by the size. It&amp;#8217;s a 15.4&amp;#8217;&amp;#8217; model with 1440&amp;#215;900 pixels. My previous 12&amp;#8217;&amp;#8217; iBook had a resolution of 1024&amp;#215;768 pixels (that&amp;#8217;s an improvement of 65 percent).&lt;/p&gt;
&lt;h2&gt;Performance&lt;/h2&gt;
&lt;p&gt;Before selling my PowerMac and iBook I made some performance tests. I used &lt;a href="http://www.geekpatrol.ca/geekbench/"&gt;GeekBench&lt;/a&gt; which is available for all major platforms and comes in 32 and 64 bit flavors. Here the scores:&lt;/p&gt;
&lt;h3&gt;Mobile computer&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;iBook (G4 1.33GHz)
	&lt;ul&gt;
		&lt;li&gt;32 Bit: 60.9&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;New MacBook Pro (Core 2 Duo 2.16GHz)
	&lt;ul&gt;
		&lt;li&gt;64 Bit: 229.9&lt;/li&gt;
		&lt;li&gt;32 Bit: 214.1&lt;/li&gt;
		&lt;li&gt;32 Bit (Rosetta): 152.3&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Desktop computer&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;PowerMac (G5 2&amp;#215;2GHz)
	&lt;ul&gt;
		&lt;li&gt;64 Bit: 158&lt;/li&gt;
		&lt;li&gt;32 Bit: 147.4&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;New PC (Core 2 Duo E6300 1.86GHz)
	&lt;ul&gt;
		&lt;li&gt;32 Bit (Windows): 217&lt;/li&gt;
		&lt;li&gt;32 Bit (Linux): 244.3&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, the upgrade from my iBook to my MacBook Pro increased the performance by 215 percent (32 Bit), by 150 percent (32 Bit &amp;#8211; Rosetta), or by 277 percent (32 Bit &amp;#8594; 64 Bit). The MacBook even beats the PowerMac! (Remember, this is only &lt;strong&gt;one&lt;/strong&gt; benchmark, it doesn&amp;#8217;t consider all components of a computer!)&lt;/p&gt;
&lt;p&gt;The most interesting observation was the performance comparison of Windows and Linux &amp;#8211; the same machine performs 12.5 percent better under Linux, but that&amp;#8217;s another story.&lt;/p&gt;
&lt;h2&gt;Pictures&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/mbp_full.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/mbp_backlight.jpg" alt="" /&gt;&lt;/p&gt;
&lt;h2&gt;End notes&lt;/h2&gt;
&lt;p&gt;I hope I have better luck with my new mobile computer than one of my friends with his MacBook. His suffered from &lt;em&gt;random shutdown problems&lt;/em&gt; (twice) and recently he &lt;em&gt;lost his hard-drive&lt;/em&gt; (somehow&amp;#8230;). Understandable that he&amp;#8217;ll think twice before buying another Mac.&lt;/p&gt;
&lt;p&gt;I switched from a Mac desktop to a PC desktop because upgrading a Mac is very expensive, but a mobile Mac is still my first choice. I prefer it not only because of it&amp;#8217;s sleep mode, but also for it&amp;#8217;s Unix underpinning and great user-experience.&lt;/p&gt;
&lt;h2&gt;Previous &lt;span class="caps"&gt;MBP&lt;/span&gt; problems&lt;/h2&gt;
&lt;p&gt;The &lt;span class="caps"&gt;MBP&lt;/span&gt; usually runs at about 50ºC (120ºF), but this goes up to 75ºC (170ºF) when compiling and I didn&amp;#8217;t notice any whining sounds.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/DJP-y1Ph9xM" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/reviews/macbook.html</feedburner:origLink></entry>
 
 <entry>
   <title>Using Google's Blogsearch</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/mnjFIfCyiaU/google_blogsearch.html" />
   <updated>2006-10-20T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/tutorials/google_blogsearch</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m using &lt;a href="http://blog.interlinked.org/reviews/hobix.html"&gt;hobix&lt;/a&gt; to power my blog. Unfortunately it requires some work to get the dynamic components up and running (search and comments).&lt;/p&gt;
&lt;p&gt;So I decided to use &lt;a href="http://blogsearch.google.com/"&gt;Google&amp;#8217;s Blogsearch&lt;/a&gt; which is pretty powerful.&lt;/p&gt;
&lt;p&gt;To include a search box on your own site paste the following code into your &lt;span class="caps"&gt;HTML&lt;/span&gt; template and set the &lt;code&gt;bl_url&lt;/code&gt; field to your own domain:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
 &amp;lt;form method="get" action="http://blogsearch.google.com/blogsearch"&amp;gt;
   &amp;lt;input name="as_q" size="15" maxlength="255" value="" type="text"&amp;gt;
   &amp;lt;input name="sa" value="Google Search" type="submit"&amp;gt;
   &amp;lt;input name="bl_url" value="blog.interlinked.org" type="hidden"&amp;gt;
   &amp;lt;input name="ie" value="ISO-8859-15" type="hidden"&amp;gt;
   &amp;lt;input name="oe" value="ISO-8859-15" type="hidden"&amp;gt;
 &amp;lt;/form&amp;gt;
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;The Blogsearch supports all standard &lt;a href="http://www.google.com/help/operators.html"&gt;operators from Google&amp;#8217;s search&lt;/a&gt;, but also &lt;a href="http://www.google.com/help/about_blogsearch.html#operators"&gt;some blog-specific ones&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;inblogtitle: search only within the title of the blog&lt;/li&gt;
	&lt;li&gt;inposttitle: search only within the title of the posting&lt;/li&gt;
	&lt;li&gt;inpostauthor: search only within the author field&lt;/li&gt;
	&lt;li&gt;blogurl: return only results starting with the given &lt;span class="caps"&gt;URL&lt;/span&gt; (that&amp;#8217;s exactly what we use for our search-box)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The biggest advantage over Google&amp;#8217;s Web-search is, that the Blogsearch almost instantly crawls your blog &lt;a href="http://www.google.com/help/blogsearch/about_pinging.html"&gt;after you&amp;#8217;ve pinged&lt;/a&gt; them, or a service monitored by Google.&lt;/p&gt;
&lt;p&gt;I use two pinging-services:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;http://pingomatic.com/&lt;/li&gt;
	&lt;li&gt;http://pingoat.com/index.php&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Only a few seconds after the ping, my feed gets fetched from Google and my article is available via the Blogsearch.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/mnjFIfCyiaU" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/google_blogsearch.html</feedburner:origLink></entry>
 
 <entry>
   <title>GMail User Interface</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/ZGO3xEtih5o/gmail_delete_button.html" />
   <updated>2006-10-18T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/misc/gmail_delete_button</id>
   <content type="html">&lt;p&gt;I really like Google&amp;#8217;s user interfaces. Most of them are really good and their &lt;a href="http://www.google.com"&gt;search interface&lt;/a&gt; changed the whole industry.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s currently only one thing I don&amp;#8217;t get &amp;#8211; the &lt;em&gt;Delete&lt;/em&gt; button in &lt;a href="http://www.gmail.com"&gt;GMail&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;GMail introduced a &lt;em&gt;Delete&lt;/em&gt; button &lt;a href="http://ars.userfriendly.org/cartoons/?id=20060125"&gt;some&lt;/a&gt; &lt;a href="http://ars.userfriendly.org/cartoons/?id=20060126"&gt;time&lt;/a&gt; &lt;a href="http://ars.userfriendly.org/cartoons/?id=20060127"&gt;in january&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Somehow they messed up their, at this point consistent, user interface. Compare the toolbars of the &lt;em&gt;Inbox&lt;/em&gt;, &lt;em&gt;Spam Folder&lt;/em&gt;, and &lt;em&gt;Trash Folder&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/gmail_toolbar_inbox.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/gmail_toolbar_spam.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/gmail_toolbar_trash.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The Inbox has the &lt;em&gt;Delete&lt;/em&gt; button on the right, while the other views have the &lt;em&gt;Delete&lt;/em&gt; button on the left. There&amp;#8217;s a small difference between &lt;em&gt;Delete&lt;/em&gt; at the Inbox and the &lt;em&gt;Delete&lt;/em&gt; within Trash and Spam (Delete Forever), but is this a reason to re-align?&lt;/p&gt;
&lt;p&gt;Why is it so annoying? I tend to remember the position of the buttons on the various interfaces I work with. Within an operating system all buttons are aligned according to a specific guideline. In different Web-applications it&amp;#8217;s usually pretty messed up, but within a single Web-application it should be consistent.&lt;/p&gt;
&lt;p&gt;This article was inspired by my clicking on &lt;em&gt;Not Spam&lt;/em&gt; button the instead of &lt;em&gt;Delete Forever&lt;/em&gt; button the tenth time.&lt;/p&gt;
&lt;p&gt;I think it&amp;#8217;s a good guideline to put the &amp;#8220;most severe&amp;#8221; action on the rightmost button, so here is a little Greasemonkey script to align the buttons for you (and me): &lt;a href="http://blog.interlinked.org/static/files/gmail_delete_button.user.js"&gt;gmail_delete_button.user.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is a little quirk with this Greasemonkey script: After you clicked on one of these buttons GMail realigns the buttons. I&amp;#8217;d be glad if someone had a suggestion&amp;#8230;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/ZGO3xEtih5o" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/misc/gmail_delete_button.html</feedburner:origLink></entry>
 
 <entry>
   <title>Why Darcs</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/ZWE7a5tVorA/why_darcs.html" />
   <updated>2006-09-10T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/reviews/why_darcs</id>
   <content type="html">&lt;p&gt;&lt;a href="http://twoday.tuwien.ac.at/ferrari"&gt;One of my colleagues&lt;/a&gt; keeps asking my why I prefer &lt;a href="http://www.darcs.net"&gt;Darcs&lt;/a&gt; over &lt;a href="http://subversion.tigris.org"&gt;Subversion&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The question isn&amp;#8217;t easy to answer. I think it&amp;#8217;s because of personal preferences and not because of objective advantages. Anyway I&amp;#8217;ll try to explain it in this article. There is also &lt;a href="http://better-scm.berlios.de/comparison/comparison.html"&gt;more objective and more extensive comparison of many version control systems&lt;/a&gt; available.&lt;/p&gt;
&lt;p&gt;Please note, I&amp;#8217;m no expert using Subversion, so please mail me if I&amp;#8217;ve got something wrong.&lt;/p&gt;
&lt;h2&gt;Changes instead of versions&lt;/h2&gt;
&lt;p&gt;Darcs builds on top of &lt;strong&gt;patches&lt;/strong&gt;. A patch is a set of changes to the repository, not only a single file.&lt;/p&gt;
&lt;p&gt;Subversion assigns version numbers to files (or better repositories). [Subversion&amp;#8217;s version numbering is much more natural than the one from &lt;span class="caps"&gt;CVS&lt;/span&gt;. It assigns the whole repository a version instead of each file a different one (like &lt;span class="caps"&gt;CVS&lt;/span&gt;). That&amp;#8217;s a huge step forward, thanks Anders Engstr&amp;ouml;m for pointing that out!]&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s an important difference, if not the most important one. When I work on a project I&amp;#8217;m not interested in versions of a file, I&amp;#8217;m interested in the changes my colleague made. Most of the time it doesn&amp;#8217;t matter to me which files were changed, I just want the feature incorporated to my local copy.&lt;/p&gt;
&lt;p&gt;Subversion doesn&amp;#8217;t allow the so called &lt;em&gt;cherry-picking&lt;/em&gt;, I can&amp;#8217;t choose changes selectively. Darcs allows to check out &lt;strong&gt;changes&lt;/strong&gt; selectively, I can check out feature X2 but not X1, even if X1 was made before X2.&lt;/p&gt;
&lt;p&gt;Since Darcs doesn&amp;#8217;t work on files, I can&amp;#8217;t check out files directly. For example if I&amp;#8217;d like to have a subdirectory of the repository, using Darcs I&amp;#8217;d have to check the whole thing out (all patches).&lt;/p&gt;
&lt;h3&gt;A little example&lt;/h3&gt;
&lt;p&gt;Imagine a system administrator using Darcs for his/her configuration files. Think of a central server which holds all users, and some specialized servers holding only a subset of them. Think of a new user for one of the specialized servers (copied from the central server):&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Using Darcs he or she can check out a patch called &amp;#8220;new user &amp;#8216;xyz&amp;#8217;&amp;#8221; and all files are updated.&lt;/li&gt;
	&lt;li&gt;Using Subversion he or she has to look through all changed files and copy the according lines to the according files. Or create the user by hand. Well, to sum it up, I don&amp;#8217;t know how to do it in Subversion or &lt;span class="caps"&gt;CVS&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Darcs:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/darcs_sysadmin_example.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Subversion:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/svn_sysadmin_example.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Of course this is a specialized example, but it illustrates the advantage of patches very well. Darcs is not black magic or something, it works usually, but has it&amp;#8217;s limits too.&lt;/p&gt;
&lt;p&gt;Subversion and &lt;span class="caps"&gt;CVS&lt;/span&gt; behave like &lt;em&gt;Network File Systems&lt;/em&gt; because you either take the latest version or leave it. If you&amp;#8217;d like to have a bug-fix, but not the new feature you&amp;#8217;ll have to merge the bug-fix into your code. As soon as you&amp;#8217;ve changed a prior version of a file you&amp;#8217;ll have to merge it with the new version in the repository&amp;#8230; .&lt;/p&gt;
&lt;p&gt;Subversion is very well suited to keep two copies in sync, but even small differences are hard to get right.&lt;/p&gt;
&lt;h2&gt;Offline usage&lt;/h2&gt;
&lt;p&gt;If you&amp;#8217;d like to use Subversion to keep track of fine grained changes you&amp;#8217;ll have to check in very often&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt; (for each little change). To do this you&amp;#8217;ll need access to the server holding your repository. But what do you do if you&amp;#8217;re on the train, in a hotel without internet, or in a small village outside the connected world?&lt;/p&gt;
&lt;p&gt;Darcs allows me to work offline but still record my changes very very fine grained (my local repository is a full fledged repository). As soon as I have connectivity I can upload my changes to the server and all my peers can take advantage of the fruits of my work (and start &lt;em&gt;cherry picking&lt;/em&gt;).&lt;/p&gt;
&lt;h2&gt;Interactive nature of Darcs&lt;/h2&gt;
&lt;p&gt;Most of Darcs&amp;#8217; commands have interactive components. This allows you to select changes for a patch even if you&amp;#8217;ve done more. Compare that to Subversion or &lt;span class="caps"&gt;CVS&lt;/span&gt;, using those you can only commit the whole file.&lt;/p&gt;
&lt;p&gt;The Darcs Wiki has a nice &lt;a href="http://darcs.net/DarcsWiki/WorkFlowsVsSubversion"&gt;comparison of interactive Darcs commands to Subversion&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Test before commiting&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://svnbook.red-bean.com/en/1.2/svn.reposadmin.create.html#svn.reposadmin.create.hooks"&gt;Subversion&lt;/a&gt; and &lt;a href="http://www.darcs.net/manual/node2.html#SECTION00210050000000000000"&gt;Darcs&lt;/a&gt; allow the testing of the code before any change to the repository happens. The difference is that Darcs tests the program on the local machine, and Subversion on the server. Darcs creates a clean copy of the code and runs the defined test suite on that code to make sure that the committed changes are working.&lt;/p&gt;
&lt;p&gt;Ad Subversion: What do you do if you develop a program for the Mac on a Mac and your Subversion repository runs on Linux?&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the end it&amp;#8217;s about you and your people. If you like Subversion and it&amp;#8217;s way of doing things it&amp;#8217;s fine. If you prefer &lt;span class="caps"&gt;CVS&lt;/span&gt; because it&amp;#8217;s the most mature one, good!&lt;/p&gt;
&lt;p&gt;If you need graphical tools to do your work, Darcs my be the worst option for you, it&amp;#8217;s still &lt;a href="http://www.spack.org/wiki/InTheBeginningWasTheCommandLine"&gt;command line oriented&lt;/a&gt;. At least I don&amp;#8217;t know of a noteworthy &lt;span class="caps"&gt;GUI&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;I like Darcs because it&amp;#8217;s simple, and doesn&amp;#8217;t clutter my projects with &lt;code&gt;.svn&lt;/code&gt; oder &lt;code&gt;.CVS&lt;/code&gt; directories. Most of the other features aren&amp;#8217;t so hot if you&amp;#8217;re the only one to use Darcs&amp;#8230; . Anyway I&amp;#8217;ve got more than a &lt;em&gt;Network File System with version support&lt;/em&gt; :-).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Little hint:&lt;/strong&gt; if you install Ian Macdonald&amp;#8217;s &lt;a href="http://www.caliban.org/bash/index.shtml"&gt;bash completion&lt;/a&gt; you can expand commands and options with &amp;lt;Tab&amp;gt;. This, of course, isn&amp;#8217;t tied to Darcs alone.&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; I wonder why I&amp;#8217;d like to check in small grained changes using Subversion because I don&amp;#8217;t have the possibility to choose which one I&amp;#8217;d like to build upon?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/ZWE7a5tVorA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/reviews/why_darcs.html</feedburner:origLink></entry>
 
 <entry>
   <title>Rethink your Web-Interfaces</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/dkhxz9qKXko/google_apps.html" />
   <updated>2006-09-09T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/misc/google_apps</id>
   <content type="html">&lt;p&gt;&lt;a href="http://www.forbes.com/technology/2006/09/07/web-based-resources-cx_bn_0907smallbizresource.html"&gt;Forbes recently published a list of Web-Applications&lt;/a&gt; for small businesses. Google won in several categories (Calendar, E-Mail, Information Managers, Spreadsheets), my question is &lt;strong&gt;why&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;Some possible explanations come to mind, like&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Google paid for the report,&lt;/li&gt;
	&lt;li&gt;the reviewer would like to work at Google,&lt;/li&gt;
	&lt;li&gt;the company likes the traffic Google sends them&amp;#8230;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Anyway, I think more important is how Google designed their applications. Not that they have more features or more buttons to press, quite the opposite, they usually feature less possibilities!&lt;/p&gt;
&lt;p&gt;Google engineers think about the interfaces for the Web and don&amp;#8217;t just stupidly copy the interfaces from (bloated) Desktop applications.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s compare &lt;a href="http://www.openoffice.org/"&gt;Open Office&amp;#8217;s (Neo Office&amp;#8217;s) Spreadsheets&lt;/a&gt;, &lt;a href="http://www.zohosheet.com/"&gt;Zoho&amp;#8217;s Spreadsheets&lt;/a&gt; and &lt;a href="http://spreadsheets.google.com"&gt;Google&amp;#8217;s Spreadsheets&lt;/a&gt; toolbars:&lt;/p&gt;
&lt;p&gt;OpenOffice:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/neooffice_spreadsheet.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Zoho:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/zoho_spreadsheet.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Google:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/google_spreadsheet.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, Zoho clearly modeled their application like a typical Desktop application. Google, on the other hand, threw out a lot of complexity and cleared the interface. They structured the menu to fit the current task (formatting, sorting or building formulas), which is natural in the Web.&lt;/p&gt;
&lt;p&gt;Of course you could argue that one doesn&amp;#8217;t need to re-learn how to use the spreadsheets in a Web-browser, but it&amp;#8217;d require to re-learn how to use the browser!&lt;/p&gt;
&lt;p&gt;Google removed the need of a &lt;em&gt;Right-Click&lt;/em&gt; for the important features (only copy, paste etc. are included). It&amp;#8217;s not very common to override the right-click within a Web browser, so customers might not expect it.&lt;/p&gt;
&lt;p&gt;They&amp;#8217;ve done the same for most of their applications, GMail offers few simple but very powerful metaphors (labels, search), the same with their calendar.&lt;/p&gt;
&lt;p&gt;So, the lesson I&amp;#8217;ve learned is to think about the different paradigms (this also goes under &lt;em&gt;know your audience&lt;/em&gt;). A Web-&lt;span class="caps"&gt;GUI&lt;/span&gt; is different from a Desktop-&lt;span class="caps"&gt;GUI&lt;/span&gt; and vice-versa. Don&amp;#8217;t just copy designs from one world to the other &amp;#8211; it&amp;#8217;s a lot of work and only a few people appreciate it in the end.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/dkhxz9qKXko" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/misc/google_apps.html</feedburner:origLink></entry>
 
 <entry>
   <title>ICFP Programming Contest</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/N7nhYJGdksE/icfp.html" />
   <updated>2006-09-08T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/icfp</id>
   <content type="html">&lt;p&gt;The &lt;a href="http://icfpcontest.org/"&gt;&lt;span class="caps"&gt;ICFP&lt;/span&gt; Programming Contest&lt;/a&gt; is a little competition just before the &lt;em&gt;International Conference on Functional Programming&lt;/em&gt;. Anyone can subscribe and attend. This year 364 teams took the challenge with their programming language of choice.&lt;/p&gt;
&lt;p&gt;The contest is not tied to functional programming languages, you can choose whatever language you want. That&amp;#8217;s the reason for this article. Which language has proven itself in this contest?&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll include the first, second and the Judge&amp;#8217;s price here.&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt; Year &lt;/td&gt;
		&lt;td&gt; First &lt;/td&gt;
		&lt;td&gt; Second &lt;/td&gt;
		&lt;td&gt; Judge &lt;/td&gt;
		&lt;td&gt;  &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; 1998 &lt;/td&gt;
		&lt;td&gt; Cilk &lt;/td&gt;
		&lt;td&gt; OCaml &lt;/td&gt;
		&lt;td&gt; J &lt;/td&gt;
		&lt;td&gt; &lt;a href="http://www.ai.mit.edu/extra/icfp-contest/"&gt;http://www.ai.mit.edu/extra/icfp-contest/&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; 1999 &lt;/td&gt;
		&lt;td&gt; OCaml &lt;/td&gt;
		&lt;td&gt; Haskell &lt;/td&gt;
		&lt;td&gt; Haskell &lt;/td&gt;
		&lt;td&gt; &lt;a href="http://web.archive.org/web/20050323030411/http://www.cs.virginia.edu/~jks6b/icfp/"&gt;http://www.cs.virginia.edu/~jks6b/icfp/&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; 2000 &lt;/td&gt;
		&lt;td&gt; OCaml &lt;/td&gt;
		&lt;td&gt; OCaml &lt;/td&gt;
		&lt;td&gt; &lt;span class="caps"&gt;GML&lt;/span&gt; &lt;/td&gt;
		&lt;td&gt; &lt;a href="http://www.cs.cornell.edu/icfp/"&gt;http://www.cs.cornell.edu/icfp/&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; 2001 &lt;/td&gt;
		&lt;td&gt; Haskell &lt;/td&gt;
		&lt;td&gt; Dylan &lt;/td&gt;
		&lt;td&gt; Erlang &lt;/td&gt;
		&lt;td&gt; &lt;a href="http://cristal.inria.fr/ICFP2001/prog-contest/"&gt;http://cristal.inria.fr/ICFP2001/prog-contest/&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; 2002 &lt;/td&gt;
		&lt;td&gt; OCaml &lt;/td&gt;
		&lt;td&gt; C &lt;/td&gt;
		&lt;td&gt; Python &lt;/td&gt;
		&lt;td&gt; &lt;a href="http://icfpcontest.cse.ogi.edu/"&gt;http://icfpcontest.cse.ogi.edu/&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; 2003 &lt;/td&gt;
		&lt;td&gt; C++ &lt;/td&gt;
		&lt;td&gt; C++ &lt;/td&gt;
		&lt;td&gt; Dylan &lt;/td&gt;
		&lt;td&gt; &lt;a href="http://www.dtek.chalmers.se/groups/icfpcontest/"&gt;http://www.dtek.chalmers.se/groups/icfpcontest/&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; 2004 &lt;/td&gt;
		&lt;td&gt; Haskell &lt;/td&gt;
		&lt;td&gt; Haskell/C++ &lt;/td&gt;
		&lt;td&gt; OCaml &lt;/td&gt;
		&lt;td&gt; &lt;a href="http://www.cis.upenn.edu/~plclub/contest/"&gt;http://www.cis.upenn.edu/~plclub/contest/&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; 2005 &lt;/td&gt;
		&lt;td&gt; Haskell &lt;/td&gt;
		&lt;td&gt; Dylan &lt;/td&gt;
		&lt;td&gt; Dylan &lt;/td&gt;
		&lt;td&gt; &lt;a href="http://icfpc.plt-scheme.org/index.html"&gt;http://icfpc.plt-scheme.org/index.html&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The results of the &lt;a href="http://icfpcontest.org/index.shtml"&gt;2006 &lt;span class="caps"&gt;ICFP&lt;/span&gt; contest&lt;/a&gt; are not included since they weren&amp;#8217;t published at the time of this writing.&lt;/p&gt;
&lt;p&gt;To sum it up:&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt; Language &lt;/td&gt;
		&lt;td&gt; First &lt;/td&gt;
		&lt;td&gt; Second &lt;/td&gt;
		&lt;td&gt; Judge &lt;/td&gt;
		&lt;td&gt; Sum &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://www.haskell.org"&gt;Haskell&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; 3 &lt;/td&gt;
		&lt;td&gt; 2 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
		&lt;td&gt; 6 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://caml.inria.fr/"&gt;OCaml&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; 3 &lt;/td&gt;
		&lt;td&gt; 2 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
		&lt;td&gt; 6 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://www.double.co.nz/dylan/"&gt;Dylan&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 2 &lt;/td&gt;
		&lt;td&gt; 2 &lt;/td&gt;
		&lt;td&gt; 4 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://en.wikipedia.org/wiki/C"&gt;C++&lt;/a&gt;++ &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
		&lt;td&gt; 2 &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 3 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://supertech.csail.mit.edu/cilk/"&gt;Cilk&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://en.wikipedia.org/wiki/C_programming_language"&gt;C&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://www.jsoftware.com/"&gt;J&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;span class="caps"&gt;GML&lt;/span&gt; &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://www.erlang.org/"&gt;Erlang&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://www.python.org"&gt;Python&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 0 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
		&lt;td&gt; 1 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Interesting, isn&amp;#8217;t it? There are few well known programming languages in this table. Haskell and OCaml both won six times! No Java, no Ruby, no Perl program made it to the top, what&amp;#8217;s up with those languages (Again, the contest is not limited to functional programming languages&amp;#8230;)?&lt;/p&gt;
&lt;p&gt;What are the possible interpretations of such a result?&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Functional programming is pretty good (at least in Haskell and OCaml)&lt;/li&gt;
	&lt;li&gt;The tasks are &amp;#8220;functional-friendly&amp;#8221; (at least we know that there are differences and you should choose your tools to suit your task)&lt;/li&gt;
	&lt;li&gt;Only teams using obscure functional programming languages submit to &lt;span class="caps"&gt;ICFP&lt;/span&gt; (&lt;a href="http://merd.sourceforge.net/pixel/language-study/icfp-figures.html"&gt;sorry, not true&lt;/a&gt;)&lt;/li&gt;
	&lt;li&gt;&lt;span class="caps"&gt;ICFP&lt;/span&gt; isn&amp;#8217;t able to run programs written in other languages&lt;/li&gt;
	&lt;li&gt;Libraries don&amp;#8217;t help you that much&lt;/li&gt;
	&lt;li&gt;Only smart people learn obscure programming languages&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Do you think your language is better than the other ones? Prove it, and sign up for the &lt;span class="caps"&gt;ICFP&lt;/span&gt; 2007 :-).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/N7nhYJGdksE" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/icfp.html</feedburner:origLink></entry>
 
 <entry>
   <title>The Programmer's Bill of Rights</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/FIWsr8MV0cQ/bill_of_rights.html" />
   <updated>2006-08-27T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/bill_of_rights</id>
   <content type="html">&lt;p&gt;Jeff Atwood over at &lt;a href="http://www.codinghorror.com"&gt;Coding Horror&lt;/a&gt; wrote &lt;a href="http://www.codinghorror.com/blog/archives/000666.html"&gt;The Programmer&amp;#8217;s Bill of Rights&lt;/a&gt; I like the idea, but some points aren&amp;#8217;t how I&amp;#8217;d like to have them.&lt;/p&gt;
&lt;p&gt;If we think of what&amp;#8217;s really essential for doing our job, the list would be very short. A table, a chair, and a computer, that&amp;#8217;s it. Unfortunately this won&amp;#8217;t work for very long. We&amp;#8217;d get back-aches from the cheap chair, headaches from the cheap monitor, and we&amp;#8217;d be pretty frustrated working with the loud, slow and unfitting computer.&lt;/p&gt;
&lt;p&gt;Please note that this is just a quick overview of things I think are important! So my &lt;em&gt;Programmer&amp;#8217;s Bill of Rights&lt;/em&gt;, or &lt;em&gt;Wishlist&lt;/em&gt; looks like that:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;Every programmer shall have a decent chair.&lt;/strong&gt;&lt;br/&gt;
Jeff is absolutely right, we&amp;#8217;re sitting most of the time. A bad back is a serious defect and hard or impossible to repair. The &lt;a href="http://www.hermanmiller.com/CDA/SSA/Product/0,,a10-c440-p8,00.html"&gt;Aeron chair&lt;/a&gt; is a very fine choice and for this kind of chair well priced.&lt;br/&gt;The table is usually not very interesting, it shouldn&amp;#8217;t be too high or too low and leave some space for the legs, duh.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Every programmer shall have a monitor setting best suited for his or her task.&lt;/strong&gt;&lt;br/&gt;
Jeff was on the right path here, but for me two monitors would not help very much. I&amp;#8217;m currently using Eclipse, and in case you don&amp;#8217;t know it, the window for the actual code is about a quarter of the whole available monitor space (subtract 1/4 on top, bottom, left, and right). So for me (and any other Eclipse user) a big monitor is much better than two monitors. On the other hand if I work with an text editor I&amp;#8217;ll probably need the help system open all the time, in this case a second monitor is priceless.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Every programmer shall choose his or her own toolset.&lt;/strong&gt;&lt;br/&gt;
Again I agree with Jeff. Whenever something is &lt;strong&gt;ours&lt;/strong&gt;, we&amp;#8217;ll handle it differently. If we chose your tools we&amp;#8217;ll do anything to show our peers that we&amp;#8217;ve chosen the right thing. We&amp;#8217;ll find new and creative ways to use our tools and master them. No two persons are equal, so everyone has his or her own preferences. We need to be able to choose a keyboard&lt;sup class="footnote" id="fnr6"&gt;&lt;a href="#fn6"&gt;6&lt;/a&gt;&lt;/sup&gt;, a mouse&lt;sup class="footnote" id="fnr7"&gt;&lt;a href="#fn7"&gt;7&lt;/a&gt;&lt;/sup&gt;,and &lt;strong&gt;most important&lt;/strong&gt; software we like to work with. Hell, the biggest flame-wars on the Internet are about Vim or Emacs, Windows or Unix. Let us choose!&lt;br/&gt;
It seems pretty weird to let the programmer choose his keyboard and mouse, but I think there are some very good arguments about it. First, a keyboard and a mouse are a host for many bacteria, I&amp;#8217;d rather dwell in my own bacteria than anyone else&amp;#8217;s. Second we get used to our equipment, I&amp;#8217;d like to have the same equipment at work as I have at home.&lt;br/&gt;
Of course not everything is a variable&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;, and we&amp;#8217;ll have to have standard equipment. But the tools we use to get our things done should be chosen by us!&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Every team or programmer shall have access to the information it, he or she needs to get the work done.&lt;/strong&gt;&lt;br/&gt;
Most of the time we&amp;#8217;ll hear something like &amp;#8220;you&amp;#8217;ve got Internet access, use it&amp;#8221;, but that&amp;#8217;s a poor argument. The quality of the information on the Internet is very variable, and finding something very specific is hard. We need to get access to online books (&lt;a href="http://pd.acm.org/"&gt;&lt;span class="caps"&gt;ACM&lt;/span&gt;&lt;/a&gt; offers access to several hundred books, &lt;a href="http://safari.oreilly.com/"&gt;O&amp;#8217;Reilly&amp;#8217;s Safari Bookshelf&lt;/a&gt; is also searchable).&lt;br/&gt;
Make customer conversations available to the programmer. Let your people get the raw material! Every post-processing loses some information.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Every team or programmer shall have an environment best suited for it, him or her.&lt;/strong&gt;&lt;br/&gt;
The environment we&amp;#8217;re working is is crucial to our work. It&amp;#8217;s important to have a quiet place to work&lt;sup class="footnote" id="fnr2"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;. Every team shall have a room for it&amp;#8217;s own. Every team shall be allowed to change the room for their own needs. Every programmer shall have space for his stuff (paperwork, pens, utilities etc.), or the room will quickly look like a chimp-cage.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Every team or programmer shall have the freedom to choose the best process and methodology for it, him or her.&lt;/strong&gt;&lt;br/&gt;
There are many, many processes and methodologies out there promising &amp;#8220;to be the best&amp;#8221;. Not every process suits every project or team, we need to choose which one is best for us. It&amp;#8217;s important to get that straight: We&amp;#8217;re building software for a customer, either internal or external, &lt;strong&gt;how&lt;/strong&gt; this is done should be our responsibility because &lt;em&gt;we&amp;#8217;re responsible&lt;/em&gt; for the product!&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Every team or programmer shall have the right to be involved in all stages of the software development.&lt;/strong&gt;&lt;br/&gt;
To get a good understanding of the project, the requirements, and the constraints we need information. So we should have the right to be at meetings with customers, managers, testers, designers etc. It&amp;#8217;s not necessary to dive in, talk with them or something, just listen, get the information needed and ask questions if something is unclear&lt;sup class="footnote" id="fnr3"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt;!&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Every team or programmer shall have time to reflect.&lt;/strong&gt;&lt;br/&gt;
History favors those who take the time to learn from it. If a project went well, sit down and discuss why and what went well. If a project went down the line, sit down and discuss what could have caused it. The important thing is to reflect what went well and maybe more important what didn&amp;#8217;t. Try to extract the essence of the success or failure. Learn from the past!&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Every team or programmer shall have time to learn something new.&lt;/strong&gt;&lt;br/&gt;
Our business is a very fast one. Whenever you stop to keep up to date we&amp;#8217;ll quickly lose tracks. We have to constantly learn new things, stay on top and try to educate ourselves as well as our peers. It&amp;#8217;s like the &lt;em&gt;Race with the Red Queen&lt;/em&gt;, we have to run as fast as we can to stay where we are&lt;sup class="footnote" id="fnr4"&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Every team of programmer shall have the freedom to criticize.&lt;/strong&gt;&lt;br/&gt;
We should take criticism seriously, we have to listen and react. It&amp;#8217;s of no use to try to change the people, usually people don&amp;#8217;t complain out of nothing. We have to take it as an opportunity. We should educate them if they got something wrong, or change our point of view and think about the criticism, maybe there is something about it&lt;sup class="footnote" id="fnr5"&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Jeff Atwood isn&amp;#8217;t the only one to write a &lt;a href="http://www.codinghorror.com/blog/archives/000666.html"&gt;Bill of Rights&lt;/a&gt;, the C2 Wiki has &lt;a href="http://c2.com/cgi/wiki?DeveloperBillOfRights"&gt;one too&lt;/a&gt; as well as a &lt;a href="http://c2.com/cgi/wiki?DeveloperBillOfResponsibilities"&gt;Bill of Responsibilites&lt;/a&gt;.&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; One man&amp;#8217;s constant is another man&amp;#8217;s variable. &amp;#8212; Alan Perlis&lt;/p&gt;
&lt;p class="footnote" id="fn2"&gt;&lt;a href="#fnr2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; I once worked in a room with &lt;strong&gt;seven people&lt;/strong&gt; and at least &lt;strong&gt;five different projects&lt;/strong&gt;, imagine the noise level in there.&lt;/p&gt;
&lt;p class="footnote" id="fn3"&gt;&lt;a href="#fnr3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; We often discussed issues which were dictated from above, but we didn&amp;#8217;t know it, so we lost hours or days discussing alternatives which simply were out of question.&lt;/p&gt;
&lt;p class="footnote" id="fn4"&gt;&lt;a href="#fnr4"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; I know of a company which is very into communicating new ideas. They preserve time to educate their people, but they forgot to consider the learning time in the first place.&lt;/p&gt;
&lt;p class="footnote" id="fn5"&gt;&lt;a href="#fnr5"&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; I once was asked to stop criticizing some product we were building. I was so perplex I couldn&amp;#8217;t say anything about it. Isn&amp;#8217;t criticism a way to improve things, or at least a pointer what is wrong with a particular product?&lt;/p&gt;
&lt;p class="footnote" id="fn6"&gt;&lt;a href="#fnr6"&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt; I used to like the Microsoft Natural Keyboard Pro while using a PC.&lt;/p&gt;
&lt;p class="footnote" id="fn7"&gt;&lt;a href="#fnr7"&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt; I once was asked to share a mouse with a colleague sitting in another room :-).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/FIWsr8MV0cQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/bill_of_rights.html</feedburner:origLink></entry>
 
 <entry>
   <title>Darcs</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/dYhm72nuUMo/darcs.html" />
   <updated>2006-08-09T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/tutorials/darcs</id>
   <content type="html">&lt;p style="float:left;"&gt;&lt;img src=".http://blog.interlinked.org/static/images/DarcsLogo.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.darcs.net"&gt;Darcs&lt;/a&gt; is a wonderful new revision control system. It&amp;#8217;s quite different from &lt;span class="caps"&gt;CVS&lt;/span&gt; or Subversion. First it has no &lt;em&gt;versions&lt;/em&gt;, second it&amp;#8217;s &lt;em&gt;distributed&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A version control system with no version? Silly me! Of course Darcs has versions, but you&amp;#8217;re responsible to &lt;strong&gt;create them yourself&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Distributed means, that there is &lt;strong&gt;no dedicated&lt;/strong&gt; central repository. Each repository exists on it&amp;#8217;s own, if you&amp;#8217;d like to have a central repository where all developers check in and out is up to you.&lt;/p&gt;
&lt;p&gt;Darcs is being developed by David Roundy, a physics professor at Berkeley. It&amp;#8217;s build upon a &amp;#8220;theory of patches&amp;#8221;. If this sounds very academic I should mention that it&amp;#8217;s programmed in Haskell. But wait! It&amp;#8217;s really good, and you don&amp;#8217;t have to have several diplomas to understand it. Quite the opposite, it&amp;#8217;s really very simple and elegant.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m writing this because I couldn&amp;#8217;t find a good introduction into Darcs. Funny enough that was my fault, because even if Darcs is an &lt;em&gt;advanced tool&lt;/em&gt; it&amp;#8217;s surprisingly simple. Anyways I&amp;#8217;ll present a quick introduction here, but for a complete reference see it&amp;#8217;s &lt;a href="http://www.darcs.net/manual"&gt;manual&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At first I had a list of commands and what they do, but honestly it would not help anyone who knows to read a manual. So I&amp;#8217;ll take another approach. I&amp;#8217;ll try to cover the common uses of a versioning system and explain how to accomplish that task with Darcs.&lt;/p&gt;
&lt;h2&gt;What I like about it&lt;/h2&gt;
&lt;h3&gt;Offline usage&lt;/h3&gt;
&lt;p&gt;You can work on your own repository on your own computer and as soon as you get connectivity, you upload the files to another repository.&lt;/p&gt;
&lt;p&gt;Compare that to &lt;span class="caps"&gt;CVS&lt;/span&gt;: You make changes, and check them in with a single command &amp;#8211; no distinction between different changes.&lt;/p&gt;
&lt;h3&gt;Cherry picking&lt;/h3&gt;
&lt;p&gt;Since Darcs operates on patches you always can choose which ones you check in, or check out. If you and your developers are disciplined enough, you can easily keep multiple branches in sync.&lt;/p&gt;
&lt;h3&gt;Documentation&lt;/h3&gt;
&lt;p&gt;Darcs is well documented, and it&amp;#8217;s included help system is also very good.&lt;/p&gt;
&lt;h3&gt;Simple yet powerful&lt;/h3&gt;
&lt;p&gt;The patch-system of Darcs is very intuitive (really!), and still very powerful.&lt;/p&gt;
&lt;h2&gt;What I don&amp;#8217;t like about it&lt;/h2&gt;
&lt;p&gt;The community behind Darcs is very able (Darcs is written in Haskell), but limited in size.&lt;/p&gt;
&lt;p&gt;Darcs&amp;#8217; tool support (&lt;span class="caps"&gt;IDE&lt;/span&gt; plugins, GUIs, additional Software) is not very extensive. But there are some nice projects, like an &lt;a href="http://sourceforge.net/projects/eclipsedarcs"&gt;Eclipse Plugin&lt;/a&gt;, a &lt;a href="http://auriga.wearlab.de/~alb/darcsweb/"&gt;Web Frontend&lt;/a&gt; and even a &lt;a href="http://www.darcs.net/DarcsWiki/TracOnDarcs"&gt;Trac module&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Installing it on Mac OS X (using DarwinPorts) is easy, but &lt;strong&gt;takes forever&lt;/strong&gt; since it depends on the Glasgow Haskell Compiler which takes a lot of time to compile itself. For Windows and Linux are binaries available. &lt;a href="http://www.riffraff.info/"&gt;Gabriele Renzi&lt;/a&gt; pointed out that there are &lt;a href="http://darcs.net/DarcsWiki/CategoryBinaries#head-c14449f675f1f36c70703538d40e79f056a69bd9"&gt;binaries for Mac OS X&lt;/a&gt; available, thanks!&lt;/p&gt;
&lt;p&gt;You have to handle the user accounts on your own. Darcs doesn&amp;#8217;t have to do anything with permissions. You either handle it via file-system permissions, &lt;span class="caps"&gt;SSH&lt;/span&gt; accounts or something like that.&lt;/p&gt;
&lt;h2&gt;Creating/Initializing a repository&lt;/h2&gt;
&lt;p&gt;If you&amp;#8217;d like to create a new repository, for a new project, or for an existing &amp;#8212; not version controlled project, &lt;code&gt;darcs initialize&lt;/code&gt; is your friend.&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
mkdir ProjectDirectory
cd ProjectDirectory
darcs initialize
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;This command creates a directory &lt;code&gt;_darcs&lt;/code&gt; which contains metadata and your &lt;strong&gt;patches&lt;/strong&gt;, simply said it&amp;#8217;s your repository. Please be sure to understand the difference between project files and repository. The &lt;em&gt;repository&lt;/em&gt; lies under the &lt;code&gt;_darcs&lt;/code&gt; directory and keeps track of the changes etc., the &lt;em&gt;project files&lt;/em&gt; are the files &lt;strong&gt;you are working on&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Adding files to version control&lt;/h2&gt;
&lt;p&gt;If you&amp;#8217;ve created some files, or would like to import your existing project files, you run &lt;code&gt;darcs add&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
darcs add * -r
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;This command adds &lt;strong&gt;all&lt;/strong&gt; files in the project directory (&lt;code&gt;-r&lt;/code&gt; means recursively include subtrees) to your repository. Please note, that your repository &lt;strong&gt;is not&lt;/strong&gt; changed by this command. It only tells Darcs that these files are under version control.&lt;/p&gt;
&lt;h2&gt;Check what you&amp;#8217;ve done since your last &amp;#8220;commit&amp;#8221;&lt;/h2&gt;
&lt;p&gt;Often you&amp;#8217;d like to see what you&amp;#8217;ve done since your last commit, and which files have changed, are new or have been removed.&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
darcs whatsnew -l
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;-l&lt;/code&gt; parameter tells Darcs to show a summary, including new files. You&amp;#8217;ll see a summary like&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
M ./modified.txt +1
R ./removed.txt
A ./underversioncontrol.txt
a ./newfile.txt
&lt;/code&gt;
&lt;/pre&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt;M&amp;#8230;&lt;/td&gt;
		&lt;td&gt;Modified file (showing the changed lines).&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;R&amp;#8230;&lt;/td&gt;
		&lt;td&gt;Removed, file is under version control, but has been removed.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;A&amp;#8230;&lt;/td&gt;
		&lt;td&gt;Added to the repository.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;a&amp;#8230;&lt;/td&gt;
		&lt;td&gt;New file, not under version control.&lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;If you ommit the &lt;code&gt;-l&lt;/code&gt; parameter, you&amp;#8217;re shown the changes within the files in Darcs&amp;#8217; own patch format. You can always get an original diff file out of Darcs if you need one.&lt;/p&gt;
&lt;h2&gt;Commiting&lt;/h2&gt;
&lt;p&gt;So far we did not change our repository. To get your current changes into the repository (&lt;span class="caps"&gt;AKA&lt;/span&gt; commit), you simply &amp;#8220;record&amp;#8221; the changes with &lt;code&gt;darcs record&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now I have to explain &lt;em&gt;patches&lt;/em&gt;. All Darcs operations work on patches. So if you commit something, you commit one or more patches, if you check something out, you check out patches etc.&lt;/p&gt;
&lt;p&gt;So, if you call &lt;code&gt;darcs record&lt;/code&gt; Darcs will ask you for each change if it should record it. One collection of changes together form a &lt;strong&gt;patch&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;After you&amp;#8217;re done with selecting your changes, you&amp;#8217;re asked to give a short patch-name, and a longer patch-description.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re sure that all changes need to be in the repository, you can use &lt;code&gt;-a&lt;/code&gt; for &lt;strong&gt;all changes&lt;/strong&gt; to skip the change selection. I usually use &lt;code&gt;darcs record -am 'my meaningful patch name'&lt;/code&gt;. This will immediately record (commit) all my changes as a single patch.&lt;/p&gt;
&lt;h2&gt;Pushing changes to other repositories&lt;/h2&gt;
&lt;p&gt;As said above, Darcs has no central repository. You can &lt;em&gt;push&lt;/em&gt; changes to any repository you&amp;#8217;ve got write access to. It&amp;#8217;s similar to a check-in in &lt;span class="caps"&gt;CVS&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;So, to push one or more patches to another repository you use &lt;code&gt;darcs push destination&lt;/code&gt;. The destination could be locally or via &lt;span class="caps"&gt;SSH&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Darcs asks for each patch which is not already in the destination repository, so you won&amp;#8217;t transfer more data than necessary.&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
darcs push versioning.company.com:/path/to/your/project
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;The above command pushes the selected patches via &lt;span class="caps"&gt;SSH&lt;/span&gt; to a remote repository, and applies them immediately.&lt;/p&gt;
&lt;p&gt;Now it&amp;#8217;s easy to manage multiple &lt;strong&gt;branches&lt;/strong&gt; the same time, just push a &lt;strong&gt;single patch&lt;/strong&gt; to &lt;strong&gt;one or more repositories&lt;/strong&gt;. You won&amp;#8217;t have to merge anything, because you keep bugfixes on both, your &lt;em&gt;&lt;span class="caps"&gt;HEAD&lt;/span&gt;&lt;/em&gt; repository, and your &lt;em&gt;&lt;span class="caps"&gt;STABLE&lt;/span&gt;&lt;/em&gt; repository in sync. But because of Darcs&amp;#8217; innovative patch system even merging is simply, just &lt;strong&gt;pick&lt;/strong&gt; the patches you need, that&amp;#8217;s it. (Take that, &lt;span class="caps"&gt;CVS&lt;/span&gt; and &lt;span class="caps"&gt;SVN&lt;/span&gt;!).&lt;/p&gt;
&lt;h2&gt;Pulling changes from other repositories&lt;/h2&gt;
&lt;p&gt;Similar to pushing changes to a repository you can also &lt;strong&gt;pull&lt;/strong&gt; them to your local repository. Just think of pulling (checking out) patches from your central repository, or from another branch of your project.&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
darcs pull versioning.company.com:/path/to/your/project
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;The above command pulls the selected patches via &lt;span class="caps"&gt;SSH&lt;/span&gt; from a remote repository, and applies them immediately.&lt;/p&gt;
&lt;p&gt;With such features it&amp;#8217;s very easy to manage multiple branches and versions of your software, or configuration files. Darcs&amp;#8217; manual calls this feature &lt;strong&gt;cherry picking&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Checking out a whole repository&lt;/h2&gt;
&lt;p&gt;To download the whole repository from you could create a new repository and download all patches from the source repository (&lt;code&gt;darcs init&lt;/code&gt; followed by &lt;code&gt;darcs pull ....&lt;/code&gt;). But there is a much more convenient and faster way:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
darcs get versioning.company.com:/path/to/your/project
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Notice, Darcs will create the project directory for you, if a directory with the same name already exists, the &lt;strong&gt;new one&lt;/strong&gt; will get a suffix (_0, _1, _2&amp;#8230;).&lt;/p&gt;
&lt;h2&gt;Creating a branch&lt;/h2&gt;
&lt;p&gt;So I&amp;#8217;ve talked about &lt;strong&gt;branches&lt;/strong&gt; earlier, how to we get one? This too is very easy, because you can think of a branch as just another repository of the same project.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/DarcsBranches.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;So to create a brach you either could &lt;strong&gt;get&lt;/strong&gt; your current repository from your local machine, or &lt;strong&gt;put&lt;/strong&gt; your local repository to your remote machine. Often some computers aren&amp;#8217;t accessible from other networks (&lt;span class="caps"&gt;NAT&lt;/span&gt;), so it&amp;#8217;s necessary to be able to &lt;strong&gt;put&lt;/strong&gt; them.&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
darcs put versioning.company.com:/path/to/your/project_STABLE
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Again, it&amp;#8217;s absolutely &lt;strong&gt;not necessary&lt;/strong&gt; to have the branch on &lt;strong&gt;another computer&lt;/strong&gt;, it&amp;#8217;s perfectly good to put them on the same machine.&lt;/p&gt;
&lt;h2&gt;Creating/Tagging a version&lt;/h2&gt;
&lt;p&gt;Darcs does not create versions for each patch you record. You have to mark versions yourself. So, to tag the &lt;strong&gt;current state of your repository&lt;/strong&gt; as a version you use &lt;code&gt;darcs tag&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
$ darcs tag
What is the version name? Version1
Finished tagging patch 'TAG Version1'
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;This versions are really what you would expect from versions if you don&amp;#8217;t know &lt;span class="caps"&gt;CVS&lt;/span&gt; or &lt;span class="caps"&gt;SVN&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;Sending patches via mail&lt;/h2&gt;
&lt;p&gt;Especially Open Source projects rely on patches from various people, but are not able to give anyone write access to the source code repository. Darcs enables you to send patches &lt;strong&gt;directly via mail&lt;/strong&gt; instead of writing directly to the repository.&lt;/p&gt;
&lt;p&gt;This gives the author of the project the possibility to check your changes and accept them or not.&lt;/p&gt;
&lt;p&gt;Darcs needs to compare your local repository with another one (preferably the one you&amp;#8217;d like to get your patch in).&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
darcs send versioning.opensource.org:/path/to/their/project
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Again, Darcs will ask you for the changes, and the email address you&amp;#8217;d like to send them. The receiver will use &lt;code&gt;darcs apply&lt;/code&gt; to apply the patch if it&amp;#8217;s good.&lt;/p&gt;
&lt;h2&gt;Looking at changes&lt;/h2&gt;
&lt;p&gt;Why use a version control system if you don&amp;#8217;t watch your changes? To get a summary of all changes made to the repository you use &lt;code&gt;darcs changes&lt;/code&gt;. It gives you a standard changelog you can include in your release notes, or changes.txt.&lt;/p&gt;
&lt;h2&gt;Assuring quality&lt;/h2&gt;
&lt;p&gt;Darcs has a lot of options, one of those is the ability to define a &lt;strong&gt;test program&lt;/strong&gt;. This test procedure is being executed every time you record a patch. The patch is only recorded, &lt;strong&gt;if the test succeeds&lt;/strong&gt; (determined via the shell-error codes).&lt;/p&gt;
&lt;p&gt;To define a test procedure or test program, you simply type:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
darcs setpref test "echo 'you really, really should test your code'"
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;This is written into your &lt;code&gt;project/_darcs/prefs/prefs&lt;/code&gt; file, you can also define a system wide test procedure in &lt;code&gt;~/.darcs/prefs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Tests are executed on a special working copy (speak: clean checkout from the repository).&lt;/p&gt;
&lt;h2&gt;Some advanced operations you might need&lt;/h2&gt;
&lt;p&gt;If you recorded a bad (buggy) patch, and you&amp;#8217;d like to remove it before anything bad happens, you can quickly use &lt;code&gt;darcs rollback&lt;/code&gt;. Rollback records an inverted patch, it &lt;strong&gt;does not&lt;/strong&gt; affect your working directory.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;d like to &lt;strong&gt;physically remove&lt;/strong&gt; patches from your repository (not working directory), &lt;code&gt;darcs unrecord&lt;/code&gt; is just for you. If you&amp;#8217;d also like to remove the changes from your working directory you should use &lt;code&gt;darcs unpull&lt;/code&gt;, please not that you&amp;#8217;ll loose the content of these patches!&lt;/p&gt;
&lt;p&gt;If you forgot some change, or found a bug in a previous patch, you can use &lt;code&gt;darcs ammend-record&lt;/code&gt; to add changes to the previous patch.&lt;/p&gt;
&lt;p&gt;A feature you&amp;#8217;re very unlikely to need is &lt;code&gt;darcs trackdown&lt;/code&gt;, but it gives a peek view of what Darcs&amp;#8217; simple but powerful patch-system is capable of.&lt;/p&gt;
&lt;p&gt;For example search for the patch that changed the password in some file:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
darcs trackdown "grep 'adminPassword: admin' configuration.cfg"
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Removes a patch after another until the command (grep in this case) returns true. Patches are removed on a special working copy, just like the tests.&lt;/p&gt;
&lt;h2&gt;Short Reference&lt;/h2&gt;
&lt;p&gt;This is a very short reference I wrote for myself, the manpage or the manuals does a better job. Maybe you&amp;#8217;ll find it useful anyways.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/DarcsCommands.png" alt="" /&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;initialize&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; sets the repository up. Can be executed in an empty directory or within your existing project directory.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;add&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; adds one or more files to the repository. You can use &lt;code&gt;darcs add * -r&lt;/code&gt; to add all files within this and subsequent directories to the repository.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;whatsnew&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; shows all changes. You can use the command line switch &lt;code&gt;-l&lt;/code&gt; to see a short summary and files which are not in the repository.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;record&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; persits the changes to the repository. Each change is a patch of it&amp;#8217;s own, so usually you&amp;#8217;ll use &lt;code&gt;record&lt;/code&gt; very frequently. &lt;code&gt;darcs record -am "comment"&lt;/code&gt; applies the same description to all open changes.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;changes&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; lists all changes (patches) recorded in this repository.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;push&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; sends patches to another repository (local or remote), usually via &lt;span class="caps"&gt;SSH&lt;/span&gt;.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;pull&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; gets patches from other repositories (local or remote).&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;remove&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; removes the file from the repository. Be aware that this will delete the file from remote repositories, but not your working repo.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;mv&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; renames or moves a file. Using this command Darcs is able to handle it without losing consistency in other repos.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;replace&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; changes tokens within your files. It&amp;#8217;s like search and replace, but has some backup built-in.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;send&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; packs a set of patches in a file and sends it via mail.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;apply&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; takes the set of patches and applies it to the current repository.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;get&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; fetches a complete repository (creates a new directory for the repository)&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;put&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; copies the current repository to another location. Creates a new directory if not already existent, and checks whether it&amp;#8217;s &amp;#8220;free&amp;#8221; (not already a Darcs repository).&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;tag&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; is used to name the current state of the repository. It&amp;#8217;s used to create versions. You can give &lt;code&gt;--tag&lt;/code&gt; parameters to &lt;code&gt;get&lt;/code&gt; for example to fetch a specific version.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;optimize&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; speeds the operations on the repository up. Most useful for remote repositories.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;amend-record&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; replaces a previous record with a new one. Has consistency problems and shouldn&amp;#8217;t be used all too often.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;rollback&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; logically removes the previous patch. Logically: the original patch remains, only a inverse patch is added. Doesn&amp;#8217;t affect the working directory.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;unrecord&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; physically removes a patch.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;revert&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; removes changes made to the working directory. It&amp;#8217;ll reflect the state of the repository.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;unrevert&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; can undo the last revert.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;unpull&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; removes a patch from the repository and from the working directory. Nothing left if you&amp;#8217;re the only repository with that patch! (Is like unrecord and revert, just without the unrevert possibility)&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;annotate&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; gives the complete history of a file or directory.&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;code&gt;trackdown&lt;/code&gt;&lt;/td&gt;
		&lt;td&gt; iteratively removes the last patch and runs the given command until it returns no more errors. For example &lt;code&gt;darcs trackdown 'grep TODO file.test'&lt;/code&gt; returns the last patch that had &amp;#8220;&lt;span class="caps"&gt;TODO&lt;/span&gt;&amp;#8221; in &amp;#8220;file.test&amp;#8221;.&lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Ommited commands: &lt;code&gt;repair&lt;/code&gt;, &lt;code&gt;dist&lt;/code&gt;, &lt;code&gt;resolve&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt;, &lt;code&gt;obliterate&lt;/code&gt;, &lt;code&gt;check&lt;/code&gt;, &lt;code&gt;setpref&lt;/code&gt;. I don&amp;#8217;t think they&amp;#8217;re important, but as you can see, Darcs isn&amp;#8217;t very bloated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Link to binaries for Mac OS X added.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/dYhm72nuUMo" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/darcs.html</feedburner:origLink></entry>
 
 <entry>
   <title>Ten questions</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/tsKq_OuytII/questions.html" />
   <updated>2006-08-01T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/questions</id>
   <content type="html">&lt;p&gt;&lt;a href="http://sztywny.titaniumhosting.com/2006/07/23/stiff-asks-great-programmers-answers/"&gt;Jaroslaw Rzeszótko sent a list of ten questions&lt;/a&gt; to some of the best known programmers in/on the net&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;. It was a great idea, I love it. The questions are very basic, but what else would you ask? Anyway I started to answer them myself, so here they are&lt;sup class="footnote" id="fnr2"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;h2&gt;How did you learn programming? Were any schools of any use? Or maybe you didn&amp;#8217;t even bother with ending any schools :)?&lt;/h2&gt;
&lt;p&gt;I taught myself &lt;span class="caps"&gt;GWA&lt;/span&gt; Basic on an Atari ST 2600. After I got a PC I started working with Turbo Pascal, Borland C++ and even Assembler.&lt;/p&gt;
&lt;p&gt;Then I chose a technical school (&lt;a href="http://www.htl-vil.ac.at/"&gt;HTBLuVA Villach&lt;/a&gt;) where I&amp;#8217;ve been re-introduced to programming, this time in a more systematic way. We were taught C, C++, Cobol (&lt;span class="caps"&gt;CICS&lt;/span&gt;), Assembler and Java which was very, very good.&lt;/p&gt;
&lt;p&gt;Now I&amp;#8217;m happy that I was forced to learn Cobol and programming for the Windows using &lt;span class="caps"&gt;MFC&lt;/span&gt; since I would have never looked at it (and hopefully never have to do so again).&lt;/p&gt;
&lt;p&gt;Later I went to the &lt;a href="http://www.tuwien.ac.at"&gt;Technical University of Vienna&lt;/a&gt;. I&amp;#8217;m not very satisfied with it&amp;#8217;s introduction courses in programming (if I had to do them, I wouldn&amp;#8217;t know much about programming), but the advanced courses are pretty interesting and challenging.&lt;/p&gt;
&lt;h2&gt;What do you think is the most important skill every programmer should possess?&lt;/h2&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt; Personal view: &lt;/td&gt;
		&lt;td&gt; Communication abilities &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Esoteric view: &lt;/td&gt;
		&lt;td&gt; Focus and taste &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;h2&gt;Do you think mathematics and/or physics are an important skill for a programmer? Why?&lt;/h2&gt;
&lt;p&gt;I don&amp;#8217;t think that physics is an important skill for programmers. Of course, everything you know helps you in some way, but we (as programmers) live in a idealized world where the laws of physics are abstracted. I think biology would be much more important than physics (think of genetic algorithms, cellular automata etc), but that&amp;#8217;s only a guess.&lt;/p&gt;
&lt;p&gt;Mathematics is very important, it&amp;#8217;s hard to explain, but it gives you the ability to analyze your programs in a easily reproducible manner. If you know math, you&amp;#8217;ll stand out of the programmer &lt;del&gt;mess&lt;/del&gt; mass.&lt;/p&gt;
&lt;h2&gt;If you had three months to learn one relatively new technology, which one would you choose?&lt;/h2&gt;
&lt;p&gt;Currently I&amp;#8217;m on the Web-side of life, so there is a lot I&amp;#8217;d like to know and learn:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Compilers are always a hot topic for me.&lt;/li&gt;
	&lt;li&gt;Mobile computing will be &lt;strong&gt;big&lt;/strong&gt; in the future.&lt;/li&gt;
	&lt;li&gt;Game-development for consoles, handhelds or even PCs would be cool too.&lt;/li&gt;
	&lt;li&gt;Artificial Intelligence and Desktop programming (on the Mac) are also interesting candidates.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What do you think makes some programmers 10 or 100 times more productive than others?&lt;/h2&gt;
&lt;p&gt;Honestly I think the most important habit is to keep learning and adapt to changing environments (call it requirements). You can be pretty fast by practicing bad habits, but learning new techniques will boost you in the mid/long term.&lt;/p&gt;
&lt;h2&gt;What are your favorite tools and why do you like them more than others?&lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;Operating System
	&lt;ul&gt;
		&lt;li&gt;I&amp;#8217;m currently a big OS X fan, it gives me a Unix OS with commercial support and applications.&lt;/li&gt;
		&lt;li&gt;Linux, because it had the biggest impact on me in my &amp;#8220;early days&amp;#8221;.&lt;/li&gt;
		&lt;li&gt;Certainly not MS Win. I don&amp;#8217;t know why, I just don&amp;#8217;t like it. Maybe because &amp;#8220;everyone&amp;#8221; has it.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;Programming Languages
	&lt;ul&gt;
		&lt;li&gt;For Web applications and scripts
		&lt;ul&gt;
			&lt;li&gt;&lt;a href="http://www.ruby-lang.org"&gt;Ruby&lt;/a&gt; it is a lot of fun and gives you immediate satisfaction. Python and Perl didn&amp;#8217;t win my heart.&lt;/li&gt;
		&lt;/ul&gt;&lt;/li&gt;
		&lt;li&gt;For larger programs (like my IMAP4 and POP3 Server)
		&lt;ul&gt;
			&lt;li&gt;Java because I&amp;#8217;m very used to it and too lazy to learn equivalent programming languages like C#. C++ is the only language I &lt;del&gt;know&lt;/del&gt; knew well enough to compare it with Java (I know these two languages far longer than all other languages combined).&lt;/li&gt;
		&lt;/ul&gt;&lt;/li&gt;
		&lt;li&gt;For Desktop applications
		&lt;ul&gt;
			&lt;li&gt;Sadly I don&amp;#8217;t really know much about it. Java is no option (&lt;span class="caps"&gt;IMO&lt;/span&gt;), and my last native desktop applications (written in C++) is about seven years old. I guess I would choose Cocoa, C or C# depending on the operating system (Mac OS X, Linux, or Windows respectively).&lt;/li&gt;
		&lt;/ul&gt;&lt;/li&gt;
		&lt;li&gt;Functional Programming (I really like this style)
		&lt;ul&gt;
			&lt;li&gt;&lt;a href="http://www.haskell.org"&gt;Haskell&lt;/a&gt; has many interesting ideas and is very powerful. Lisp/Scheme are nice too, but I&amp;#8217;m more into Haskell.&lt;/li&gt;
		&lt;/ul&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;Text Editor
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="http://www.macromates.com"&gt;TextMate&lt;/a&gt; it made me dream &amp;#8211; you can still make money with a text editor.&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.vim.org"&gt;VIm&lt;/a&gt; (although I could use some practice with it) because it is omnipresent.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;Version Control System
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="http://www.darcs.net"&gt;Darcs&lt;/a&gt; innovative and intuitive.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;Shell
	&lt;ul&gt;
		&lt;li&gt;Bash + &lt;a href="http://www.caliban.org/bash/"&gt;Bash Completion&lt;/a&gt; (nevery &lt;strong&gt;really&lt;/strong&gt; looked at something else).&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;Database Engine
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="http://www.sqlite.org"&gt;SQLite&lt;/a&gt; simple and fast (with &lt;a href="http://en.wikipedia.org/wiki/Duck_typing"&gt;duck-typing&lt;/a&gt;).&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;Other tools
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="http://www.mozilla.com/firefox/"&gt;Firefox&lt;/a&gt; it&amp;#8217;s extensible and does it&amp;#8217;s job.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What is your favorite book related to computer programming?&lt;/h2&gt;
&lt;p&gt;I really like Donald Knuth&amp;#8217;s &lt;a href="http://www.amazon.de/o/ASIN/0201485419/httwwwintxorg-21/"&gt;The Art of Computer Programming 1-3&lt;/a&gt;. I never finished a single book of this series, but I know that Mr. Knuth put a tremendous amount of work into them&lt;sup class="footnote" id="fnr3"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt;. They simply have the touch of &amp;#8220;old school&amp;#8221; and superiority.&lt;/p&gt;
&lt;p&gt;I also love &lt;a href="http://www.amazon.de/o/ASIN/0321146530/httwwwintxorg-21/"&gt;Test Driven Development&lt;/a&gt; by Kent Beck. It&amp;#8217;s only a small book but had a &lt;strong&gt;huge&lt;/strong&gt; impact on my programming style.&lt;/p&gt;
&lt;p&gt;Then I&amp;#8217;d like to include &lt;a href="http://www.amazon.de/o/ASIN/0135974445/httwwwintxorg-21/"&gt;Agile Software Development. Principles, Patterns, and Practices&lt;/a&gt; from Robert C. Martin which gave me an idea what &amp;#8220;professional software development&amp;#8221; could be.&lt;/p&gt;
&lt;p&gt;More on the &amp;#8220;soft&amp;#8221; side is &lt;a href="http://www.amazon.de/o/ASIN/020161622X/httwwwintxorg-21/"&gt;The Pragmatic Programmer&lt;/a&gt; from Andrew Hunt and Dave Thomas.&lt;/p&gt;
&lt;h2&gt;What is your favorite book &lt;span class="caps"&gt;NOT&lt;/span&gt; related to computer programming?&lt;/h2&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt; Fiction &lt;/td&gt;
		&lt;td&gt; Neil Stephenson&amp;#8217;s &amp;#8220;Cryptonomicon&amp;#8221;: &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Non-Fiction &lt;/td&gt;
		&lt;td&gt; Edwart Tufte&amp;#8217;s &lt;a href="http://www.amazon.de/o/ASIN/0961392142/httwwwintxorg-21/"&gt;The Visual Display of Quantitative Information&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Soft Skills &lt;/td&gt;
		&lt;td&gt; Tom DeMarco, Timothy Lister &lt;a href="http://www.amazon.de/o/ASIN/0932633439/httwwwintxorg-21/"&gt;Peopleware&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;h2&gt;What are your favorite music bands?&lt;/h2&gt;
&lt;p&gt;System of a Down, Pearl Jam, Alanis Morissette&amp;#8230;&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; I think only because they are very present in/on the net, they are not necessarily the best programmers in the world.&lt;/p&gt;
&lt;p class="footnote" id="fn2"&gt;&lt;a href="#fnr2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; Please not that I don&amp;#8217;t consider myself anywhere near the people Jaroslaw asked.&lt;/p&gt;
&lt;p class="footnote" id="fn3"&gt;&lt;a href="#fnr3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; Almost any hard problem is scared only by opening one of them.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/tsKq_OuytII" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/questions.html</feedburner:origLink></entry>
 
 <entry>
   <title>Don't over-reuse</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/AeiNWnLo0k0/frameworks.html" />
   <updated>2006-07-20T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/frameworks</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m no big fan of frameworks. This comes from bad experience with a framework drawn out of a specialized project. It had to be used in &lt;strong&gt;every&lt;/strong&gt; project we had to implement whether it was appropriate or not. The argument was something like &amp;#8220;it provides features you&amp;#8217;d have to implement yourself, so it saves you time&amp;#8221;. Usually these features would take about one hour to half a day to implement new &amp;#8212; exactly fitting the problem. But we had to take all the clutter and deal with it. This was about six years ago, and as far as I know they still use this exact framework&amp;#8230; .&lt;/p&gt;
&lt;p&gt;Reuse is a good thing, we all know that, and we all draw our benefits from it. But you can certainly overdo it, not every project fits a specific framework.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://twoday.tuwien.ac.at/ferrari/stories/91075/"&gt;Ben&lt;/a&gt; had a link to recordings of the last RailsConf (and insisted that I watch them) where Martin Fowler and David Heinemeier Hansson talked about what the essence of Rails really is. It does fit a few particular cases very well, but it doesn&amp;#8217;t solve &lt;strong&gt;all&lt;/strong&gt; problems for Web developers. &lt;a href="http://blog.scribestudio.com/articles/2006/07/03/martin-fowler-railsconf-2006-keynote-address"&gt;Fowler&amp;#8217;s talk&lt;/a&gt; is a bit more general on Software development, and &lt;a href="http://blog.scribestudio.com/articles/2006/07/09/david-heinemeier-hansson-railsconf-2006-keynote-address"&gt;DHH&amp;#8217;s talk&lt;/a&gt; presents new ideas for the upcoming version of Rails, but starts with the philosophy and the goal as well as the non-goals of Rails. Both talks are highly recommended.&lt;/p&gt;
&lt;p&gt;The reason I write about it is &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=167168"&gt;Bruce Eckel&amp;#8217;s articel &amp;#8216;When Reuse Goes Bad&amp;#8217;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;This resulted in classic framework-itis. The contractor was no longer just trying to solve the customer&amp;#8217;s problem, they were trying to solve all problems that looked like it. So for that reason alone the project would have required 10x the original time and money.&lt;/cite&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=167168"&gt;Read it, it&amp;#8217;s a short one&lt;/a&gt;. I really felt affected by it.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/AeiNWnLo0k0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/frameworks.html</feedburner:origLink></entry>
 
 <entry>
   <title>Mental workout</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/B8Jm6fOOgNs/games.html" />
   <updated>2006-06-25T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/misc/games</id>
   <content type="html">&lt;p&gt;According to &lt;a href="http://www.popsci.com/popsci/science/61994314e58fb010vgnvcm1000004eecbccdrcrd.html"&gt;this article from Popular Science&lt;/a&gt; thinking really hard causes your brain to consume &lt;strong&gt;15 times&lt;/strong&gt; more calories than in &amp;#8220;stand-by mode&amp;#8221;. The calorie consumption goes up from 0.1 calorie per minute to 1.5 calories per minute.&lt;/p&gt;
&lt;h2&gt;So let&amp;#8217;s start our mental workout with some easy warmup exercises&lt;/h2&gt;
&lt;h3&gt;3D Logic&lt;/h3&gt;
&lt;p&gt;In &lt;a href="http://www.thatvideogamesite.com/play.php?id=392"&gt;3D Logic&lt;/a&gt; you&amp;#8217;ll have to connect two colored fields with a line in the same color on a 3D cube.&lt;/p&gt;
&lt;p&gt;On this cube (1st level)&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/3DLogic.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;you&amp;#8217;ll have to connect the two red squares with a red line, the two violet ones with a violet line and the green one&amp;#8230; you got it. This game takes some time, but don&amp;#8217;t be fooled it gets pretty hard in later levels!&lt;/p&gt;
&lt;h2&gt;Don&amp;#8217;t be tired! Jump in to the next exercise&lt;/h2&gt;
&lt;h3&gt;Planetary&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://www.planarity.net/"&gt;Planetary&lt;/a&gt; requires you to make a non-planar graph planar (so that no edges intersect).&lt;/p&gt;
&lt;p&gt;Transform this graph (3rd level):&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/NonPlanar.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;to this one&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/Planar.png" alt="" /&gt;&lt;/p&gt;
&lt;h2&gt;At the end some stretching exercises&lt;/h2&gt;
&lt;h3&gt;Sudoku&lt;/h3&gt;
&lt;p&gt;Of course Sudoku is &lt;strong&gt;the&lt;/strong&gt; classic, it&amp;#8217;s everywhere and of course online too &amp;#8212; at &lt;a href="http://www.websudoku.com/"&gt;WebSudoku&lt;/a&gt; for example. Currently there are also some multiplayer variants coming up, &lt;a href="http://www.sudokucombat.com/"&gt;Sudoku Combat&lt;/a&gt; is a popular one.&lt;/p&gt;
&lt;p&gt;Screenshot of SudokuCombat:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/SudokuCombat.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;And? Lost some weight?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/B8Jm6fOOgNs" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/misc/games.html</feedburner:origLink></entry>
 
 <entry>
   <title>The year 2038 problem</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/f34sc-gueSA/2038.html" />
   <updated>2006-06-21T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/misc/2038</id>
   <content type="html">&lt;p&gt;I just found some information on an upcoming problem, &lt;a href="http://www.deepsky.com/~merovech/2038.html"&gt;the year 2038 problem&lt;/a&gt;. On that page is also an program to test whether your operating system has a problem or not.&lt;/p&gt;
&lt;p&gt;In summary: the system time is usually stored as seconds since 1970 in a 32-bit register (or variable). On 2038-01-19 at 03:14:07 the register will overflow&amp;#8230; . The solution is to switch to an 64-bit register (sufficient more than 4,000,000,000,000 years).&lt;/p&gt;
&lt;p&gt;Usually not only the operating system has to be tuned, all time variables have to be large enough. 32 years aren&amp;#8217;t that much for some programs (I&amp;#8217;ve heard :-)). &lt;span class="caps"&gt;BIOS&lt;/span&gt; variants may also have problems on that day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Some operations do have that problem now! Just think of an average of two dates after Jan 2004 &lt;code&gt;(a+b)/2&lt;/code&gt;! &lt;code&gt;a+b&lt;/code&gt; is already too large for 32 bits.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;I couldn&amp;#8217;t resist to check it on my systems&lt;/h2&gt;
&lt;p&gt;Linux currently has a problem, Mac OS X doesn&amp;#8217;t.&lt;/p&gt;
&lt;h3&gt;Mac OS X Tiger on a G5&lt;/h3&gt;
&lt;pre&gt;
Tue Jan 19 03:14:01 2038
Tue Jan 19 03:14:02 2038
Tue Jan 19 03:14:03 2038
Tue Jan 19 03:14:04 2038
Tue Jan 19 03:14:05 2038
Tue Jan 19 03:14:06 2038
Tue Jan 19 03:14:07 2038
Tue Jan 19 03:14:07 2038
Tue Jan 19 03:14:07 2038
Tue Jan 19 03:14:07 2038
&lt;/pre&gt;
&lt;h3&gt;Mac OS X Tiger on a G4&lt;/h3&gt;
&lt;pre&gt;
Tue Jan 19 03:14:01 2038
Tue Jan 19 03:14:02 2038
Tue Jan 19 03:14:03 2038
Tue Jan 19 03:14:04 2038
Tue Jan 19 03:14:05 2038
Tue Jan 19 03:14:06 2038
Tue Jan 19 03:14:07 2038
Tue Jan 19 03:14:07 2038
Tue Jan 19 03:14:07 2038
Tue Jan 19 03:14:07 2038
&lt;/pre&gt;
&lt;h3&gt;Linux (Kernel 2.6.16)&lt;/h3&gt;
&lt;pre&gt;
Tue Jan 19 03:14:01 2038
Tue Jan 19 03:14:02 2038
Tue Jan 19 03:14:03 2038
Tue Jan 19 03:14:04 2038
Tue Jan 19 03:14:05 2038
Tue Jan 19 03:14:06 2038
Tue Jan 19 03:14:07 2038
Fri Dec 13 20:45:52 1901
Fri Dec 13 20:45:52 1901
Fri Dec 13 20:45:52 1901
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/f34sc-gueSA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/misc/2038.html</feedburner:origLink></entry>
 
 <entry>
   <title>Manage your people</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/Z-3MmYFi9Mk/management.html" />
   <updated>2006-04-22T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/biz/management</id>
   <content type="html">&lt;p&gt;Whereas I don&amp;#8217;t have the experience to write about it, I&amp;#8217;d like to show some lecture notes and summaries about &lt;em&gt;leading in high-tech&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Science, technology and tools often hide the most important fact: &lt;strong&gt;your people are your capital!&lt;/strong&gt; The better your people the better your products. Of course you can hire highly trained people, but it&amp;#8217;s your obligation to give them space and opportunity to evolve.&lt;/p&gt;
&lt;p&gt;Your employees are highly motivated and highly trained after their schooling, but all to often the get demotivated far too fast. Why? One thing I&amp;#8217;ve blogged about earlier is to tell them &lt;strong&gt;how to do&lt;/strong&gt; their task instead the goal. This leads to an interest conflict,  the requirements may conflict with the employees liability. Simply put: I can&amp;#8217;t be responsible for things I was forced to do.&lt;/p&gt;
&lt;p&gt;Software Engineering is somehow special in some cases:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Ideas are the driving force&lt;/li&gt;
	&lt;li&gt;The outcome is often unsure&lt;/li&gt;
	&lt;li&gt;Research leads to knowledge gain; Development to products; these two often get mixed up and lead to nowhere&lt;/li&gt;
	&lt;li&gt;Progress is hard to measure (90% syndrome)&lt;/li&gt;
	&lt;li&gt;Unsafe starting-point (changing requirements; incomplete foundation)&lt;/li&gt;
	&lt;li&gt;High complexity of modern software products&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To support the worker, you must make sure&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;to give them enough freedom to think&lt;/li&gt;
	&lt;li&gt;to enable quiet and uninterrupted working&lt;/li&gt;
	&lt;li&gt;to enable communication between the people&lt;/li&gt;
	&lt;li&gt;to supply the needed tools&lt;/li&gt;
	&lt;li&gt;not to condemn errors &amp;#8211; these are necessary within a creative environment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Important points to keep:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;bad ideas lead to bad products (often the first idea won&amp;#8217;t be the best)&lt;/li&gt;
	&lt;li&gt;the best idea won&amp;#8217;t lead to success if the routine work fails&lt;/li&gt;
	&lt;li&gt;methods enable creative thinking (they free you from thinking about routine tasks)&lt;/li&gt;
	&lt;li&gt;processes make projects &lt;strong&gt;faster&lt;/strong&gt;! If a process slows you down (long-term), it&amp;#8217;s the wrong one.&lt;/li&gt;
	&lt;li&gt;your people &lt;strong&gt;want&lt;/strong&gt; to be proud of their work, make sure they &lt;strong&gt;can&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/Z-3MmYFi9Mk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/biz/management.html</feedburner:origLink></entry>
 
 <entry>
   <title>Growth</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/bNgxrnIvLYw/growth.html" />
   <updated>2006-04-22T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/biz/growth</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve seen companies which try hard to grow&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;. I often can&amp;#8217;t see the point in getting more people to work for them. Investing in the current people pays much more, I think. If you take the span of bad people to very good people which can be &lt;strong&gt;ten times&lt;/strong&gt; more productive&lt;sup class="footnote" id="fnr2"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;, wouldn&amp;#8217;t it be worth to invest five times more money and time into these people than hiring more and more? Every single person increases the communication effort and slows the whole organization down. Whereas a slim, highly productive team increases the quality and lowers communication effort.&lt;/p&gt;
&lt;h2&gt;More productive?&lt;/h2&gt;
&lt;p&gt;There are many factors which influence the productivity of people in software development.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Speed (Function Points per Week)&lt;/li&gt;
	&lt;li&gt;Defect rate (bugs per Function Point)&lt;/li&gt;
	&lt;li&gt;Communication effort (knows how to use Google and Books)&lt;/li&gt;
	&lt;li&gt;Cost (Cost per Function Point)&lt;/li&gt;
	&lt;li&gt;many many more&amp;#8230;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lets compare two groups of developers, one slightly better than the other&lt;sup class="footnote" id="fnr5"&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt; Developer &lt;/td&gt;
		&lt;td&gt; FPs/Week &lt;/td&gt;
		&lt;td&gt; Bugs/Fp &lt;/td&gt;
		&lt;td&gt; Euro/Week &lt;/td&gt;
		&lt;td&gt; Euro/FP &lt;/td&gt;
		&lt;td&gt; Additional communication-effort &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; A &lt;/td&gt;
		&lt;td&gt; 100 &lt;/td&gt;
		&lt;td&gt; 0.01 &lt;/td&gt;
		&lt;td&gt; 1200 &lt;/td&gt;
		&lt;td&gt; 12 &lt;/td&gt;
		&lt;td&gt; 0.05 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; B &lt;/td&gt;
		&lt;td&gt;  66 &lt;/td&gt;
		&lt;td&gt; 0.02 &lt;/td&gt;
		&lt;td&gt; 800  &lt;/td&gt;
		&lt;td&gt; 12 &lt;/td&gt;
		&lt;td&gt; 0.10 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;So, developer A is clearly more productive than developer B, but costs more.&lt;/p&gt;
&lt;p&gt;Imagine a project with 1,000 Function Points. It has to be code complete in five weeks.&lt;/p&gt;
&lt;h3&gt;Group of A-Developers&lt;/h3&gt;
&lt;p&gt;1,000 Function Points in five weeks are 200 Function Points per week. Our team has to consist of three A-developers. Ideally, three developers produce 300 Function Points, but we have to consider the communication effort: (3 &amp;#215; 100) x (0.95&lt;sup&gt;3&lt;/sup&gt;) = max. 257 Function Points. Cost: 18,000 Euro with a combined defect rate of 0.0297&lt;sup class="footnote" id="fnr3"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3&gt;Group of B-Developers&lt;/h3&gt;
&lt;p&gt;This group has to consist of six developers. (6 &amp;#215; 66) x (0.9&lt;sup&gt;6&lt;/sup&gt;) = max 210 Function Points. Cost: 24,000 Euro with a combined defect rate of 0.114.&lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;As you can see, a few developers which are slightly better than another group can easily outperform a double sized team:&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt; Team &lt;/td&gt;
		&lt;td&gt; Number of developers &lt;/td&gt;
		&lt;td&gt; max. FPs &lt;/td&gt;
		&lt;td&gt; Cost &lt;/td&gt;
		&lt;td&gt; Defect rate &lt;/td&gt;
		&lt;td&gt; Communication effort &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; A &lt;/td&gt;
		&lt;td&gt; 3 &lt;/td&gt;
		&lt;td&gt; 257 &lt;/td&gt;
		&lt;td&gt; 18,000 &lt;/td&gt;
		&lt;td&gt; 0.0297 &lt;/td&gt;
		&lt;td&gt; 0.1426 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; B &lt;/td&gt;
		&lt;td&gt; 6 &lt;/td&gt;
		&lt;td&gt; 210 &lt;/td&gt;
		&lt;td&gt; 24,000 &lt;/td&gt;
		&lt;td&gt; 0.114  &lt;/td&gt;
		&lt;td&gt; 0.4686 &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;You could easily pay the A-Developers the double amount of the B-Developers and you would still produce a better&lt;sup class="footnote" id="fnr4"&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt; product in the same time with the same expenses! Additionally the A-team still has more capacity left for changing requirements or unforeseen problems.&lt;/p&gt;
&lt;p&gt;Again, wouldn&amp;#8217;t it be far better to support and develop your current staff than simply adding more people?&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; In terms of &amp;#8220;hiring people&amp;#8221;.&lt;/p&gt;
&lt;p class="footnote" id="fn2"&gt;&lt;a href="#fnr2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; The numbers came from two different sources. The first one is senior Siemens manager, and the second one is Paul Graham.&lt;/p&gt;
&lt;p class="footnote" id="fn3"&gt;&lt;a href="#fnr3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; One minus the probability of no error: 1 &amp;#8211; 0.99&lt;sup&gt;3&lt;/sup&gt;&lt;/p&gt;
&lt;p class="footnote" id="fn4"&gt;&lt;a href="#fnr4"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; More features or superior usability and less defects.&lt;/p&gt;
&lt;p class="footnote" id="fn5"&gt;&lt;a href="#fnr5"&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; &lt;em&gt;Never&lt;/em&gt; trust a statistic you didn&amp;#8217;t fake yourself.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/bNgxrnIvLYw" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/biz/growth.html</feedburner:origLink></entry>
 
 <entry>
   <title>The First Idea</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/lrNQUBNakTE/thefirstidea.html" />
   <updated>2006-04-21T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/biz/thefirstidea</id>
   <content type="html">&lt;p&gt;I don&amp;#8217;t like &lt;em&gt;first ideas&lt;/em&gt;. Most people working with me may have painfully experienced that&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;I really think that idea generation is vital in our business. We can&amp;#8217;t afford (anymore) to take the first idea and start working. Knowing the alternatives is much too important. All too often I see people thinking of a problem and the first idea that seems to make sense is it. These (non)efforts result in changing directions in the middle of the development, or in starting over. Both very expensive experiences.&lt;/p&gt;
&lt;p&gt;Sometimes the &lt;em&gt;fist glance&lt;/em&gt; (see Blink&lt;sup class="footnote" id="fnr2"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;) is very important and a very powerful tool. But in this case, with systems more complex than most other products in the world, that won&amp;#8217;t work.&lt;/p&gt;
&lt;p&gt;I really enjoyed Scott Berkuns &amp;#8220;The Art of Project Management&lt;sup class="footnote" id="fnr3"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt;&amp;#8221;. Especially because he dedicated some pages on that problem. When we start to think about a problem we should explore the problem space as far as possible&lt;sup class="footnote" id="fnr4"&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt;. Know what&amp;#8217;s allowed to do and think of as much possible solution within these boundaries as possible. At some point the solution space stops expanding and collapses. This is partly because some solutions are not feasible, and partly because the solutions overlap. At the end you should have a few &lt;strong&gt;very&lt;/strong&gt; distinct solution-proposals. Now it&amp;#8217;s time to analyze those. Do they really solve your problem? Is this what the users want? Is it feasible? How much does it cost?&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/Solution%20Sapce.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;At the end of this process you should have &lt;strong&gt;one&lt;/strong&gt; solution which is very likely significantly different from the &lt;em&gt;first idea&lt;/em&gt;. &lt;strong&gt;And&lt;/strong&gt; you have a high chance that you&amp;#8217;ve chosen one of the best solutions possible.&lt;/p&gt;
&lt;p&gt;Bad ideas simply lead to bad products, but also good ideas lead to bad products if the rest fails. Nevertheless, many of the failing projects&lt;sup class="footnote" id="fnr4"&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt; have problems with their foundation (requirements and ideas) than with the implementation (design and code). Unfortunately changing the foundation gets very expensive the further the project develops.&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; On the other hand, my blog-articles are rarely more than a blink of an early idea.&lt;/p&gt;
&lt;p class="footnote" id="fn2"&gt;&lt;a href="#fnr2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; &lt;a href="http://www.amazon.de/o/ASIN/0316001058/httwwwintxorg-21/"&gt;Blink&lt;/a&gt; by Malcolm Gladwell&lt;/p&gt;
&lt;p class="footnote" id="fn3"&gt;&lt;a href="#fnr3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; &lt;a href="http://www.amazon.de/o/ASIN/0596007868/httwwwintxorg-21/"&gt;The Art of Project Management&lt;/a&gt; by Scott Berkun&lt;/p&gt;
&lt;p class="footnote" id="fn4"&gt;&lt;a href="#fnr4"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; You have to know when to stop.&lt;/p&gt;
&lt;p class="footnote" id="fn5"&gt;&lt;a href="#fnr5"&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; Number vary, but standish offered these: 31% are cancelled before completion, and 22% slip their schedules. Most of them had problems with their foundations.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/lrNQUBNakTE" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/biz/thefirstidea.html</feedburner:origLink></entry>
 
 <entry>
   <title>The Pragmatic Programmer</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/DwvECR3DJro/pragmatic_programmers.html" />
   <updated>2006-04-05T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/reviews/pragmatic_programmers</id>
   <content type="html">&lt;p&gt;&lt;a href="http://www.amazon.de/o/ASIN/020161622X/httwwwintxorg-21/"&gt;&lt;img src="http://images-eu.amazon.com/images/P/020161622X.03.MZZZZZZZ.jpg" style="float:left; margin-right:10px;" alt="" /&gt;&lt;/a&gt; Wow, that&amp;#8217;s a great book! I own over 80 non-fiction books but only few of them excite me that much. &lt;a href="http://www.amazon.de/o/ASIN/020161622X/httwwwintxorg-21/"&gt;The Pragmatic Programmer from journeyman to master&lt;/a&gt; from Andrew Hunt and David Thomas is one of those. It&amp;#8217;s stuffed full with practical wisdom and tips you can start using from the moment you read it.&lt;/p&gt;
&lt;p&gt;They discuss all relevant topics of programming and software development, starting from text editors, IDEs, code generation, command line versus &lt;span class="caps"&gt;GUI&lt;/span&gt; etc&amp;#8230; to estimation, handling requirements and documentation. It&amp;#8217;s fantastic and really fun to read, too sad it has only 300 pages.&lt;/p&gt;
&lt;p&gt;Usually the quotes on the back-flap of any book should be handled with care, but Ward Cunninghams quote &lt;cite&gt;If I&amp;#8217;m putting together a project, it&amp;#8217;s the authors of this book that I want. &amp;#8230; And failing that I&amp;#8217;d settle for people who&amp;#8217;ve read their book.&lt;/cite&gt; doesn&amp;#8217;t really surprise me after reading just a few chapters.&lt;/p&gt;
&lt;p&gt;(The second one equally full of wisdom, but with another focus, is Robert C. Martins &lt;a href="http://www.amazon.de/o/ASIN/0135974445/httwwwintxorg-21/"&gt;Agile Software Development. Principles, Patterns, and Practices&lt;/a&gt;. Before buying several books on Design Patterns, Agile Methodologies and Software Development guidelines buy this one.)&lt;/p&gt;
&lt;p&gt;Even if these books are &lt;em&gt;from programmers for programmers&lt;/em&gt;, they&amp;#8217;re extremely well written (meaning they don&amp;#8217;t use nested parentheses (like me))!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/DwvECR3DJro" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/reviews/pragmatic_programmers.html</feedburner:origLink></entry>
 
 <entry>
   <title>Why you should use a plain text editor for programming</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/u_fPvSiBaUk/texteditor_code_generation.html" />
   <updated>2006-04-03T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/texteditor_code_generation</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m always impressed if someone codes like it&amp;#8217;s all he or she has ever done, without &lt;span class="caps"&gt;IDE&lt;/span&gt; and still n-times faster than anyone with an &lt;span class="caps"&gt;IDE&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;During the past few years I&amp;#8217;ve done a lot of Java coding. I&amp;#8217;ve used Eclipse most of the time, but until now I didn&amp;#8217;t realize how little I really know about Java&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt; &amp;#8212; my skills largely depended on my &lt;span class="caps"&gt;IDE&lt;/span&gt; of choice.&lt;/p&gt;
&lt;p&gt;Most of the time I don&amp;#8217;t have a clue where (in which package) a specific class lies, as well as I don&amp;#8217;t know (even roughly) what exceptions are thrown. For these tasks I asked my &lt;span class="caps"&gt;IDE&lt;/span&gt; to generate the code I needed (&lt;code&gt;import&lt;/code&gt;, &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; or &lt;code&gt;throws&lt;/code&gt; statements).&lt;/p&gt;
&lt;p&gt;The last few days I used &lt;span class="caps"&gt;ANTLR&lt;/span&gt; to generate a parser. I didn&amp;#8217;t use an &lt;span class="caps"&gt;IDE&lt;/span&gt; (there is none for &lt;span class="caps"&gt;ANTLR&lt;/span&gt; 2 available for free), which meant I had to refer to the Java &lt;span class="caps"&gt;API&lt;/span&gt; to check whether my imports are right, how this or that method is named exactly and which arguments it&amp;#8217;ll take (what Eclipse has done so far. It is to be blamed that I only know approximately the first three characters of a method name&lt;sup class="footnote" id="fnr2"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;).&lt;/p&gt;
&lt;p&gt;If we are coding for productivity, in our day job or where time matters more than sharpening our skills, it&amp;#8217;s fine (and sometimes crucial) to use an &lt;span class="caps"&gt;IDE&lt;/span&gt;. But if we want to learn something and get better (smarter) at our tasks it actually does harm: we&amp;#8217;ll end up thinking &lt;em&gt;man that&amp;#8217;s easy I must know pretty much everything about this or that&lt;sup class="footnote" id="fnr5"&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt;&amp;#8230;&lt;/em&gt; where in fact we only know how to use our &lt;span class="caps"&gt;IDE&lt;/span&gt; and don&amp;#8217;t know s##t about the language itself&lt;sup class="footnote" id="fnr3"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Another dangerous thing with code generators is, that it seems pretty easy to get up and running with a mid-sized application. We write a bit, generate a lot and we&amp;#8217;re ready to go, isn&amp;#8217;t that so? No, only at the beginning! If we (or someone else) need to change something in that code, maybe weeks or months later we have to understand every bit of the generated code (&lt;a href="http://twoday.tuwien.ac.at/ferrari/stories/9899/"&gt;Ben has written about that too&lt;/a&gt;), now we&amp;#8217;re screwed. If the code looks messy why should anyone bother to do his/her best to make clean changes?&lt;/p&gt;
&lt;p&gt;If it&amp;#8217;s easy to copy and generate lots of code why should one bother and think about &lt;strong&gt;abstraction&lt;/strong&gt;, &lt;strong&gt;generalization&lt;/strong&gt; and stuff? If I had to write getters and setters by hand, I would do anything to avoid it. Maybe (just maybe&amp;#8230;) I&amp;#8217;d just start designing my programs, making a real &lt;a href="http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html"&gt;O-O design&lt;/a&gt; (or write a generator to write them for me, but that&amp;#8217;s another story).&lt;/p&gt;
&lt;p&gt;The previous problem can easily be avoided by hiding the generating the code. In Lisp one writes macros to generate code at compile time, xDoclet generates code as it&amp;#8217;s own step, &lt;span class="caps"&gt;EJB&lt;/span&gt; 3 generates code at compile time too.&lt;/p&gt;
&lt;p&gt;Now, what&amp;#8217;s the point? Use a plain text-editor&lt;sup class="footnote" id="fnr4"&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt; for educational purposes and avoid generating too much code with your &lt;span class="caps"&gt;IDE&lt;/span&gt; on your day job.&lt;/p&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; &lt;em&gt;Java&lt;/em&gt; in terms of packages structure, method names etc. Meta-concepts like algorithms, techniques, patterns etc. are out of question.&lt;/p&gt;
&lt;p class="footnote" id="fn2"&gt;&lt;a href="#fnr2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; That&amp;#8217;s a great example for a quote out of Donald Normans book &lt;a href="http://www.amazon.de/exec/obidos/ASIN/0465067107/httwwwintxorg-21/"&gt;The Design of Everyday Things&lt;/a&gt;  &lt;em&gt;Knowledge in the head, and in the world: Precise behavior can emerge from imprecise knowledge&lt;/em&gt;, and, of course his &lt;a href="http://www.amazon.de/exec/obidos/ASIN/0201626950/httwwwintxorg-21/"&gt;Things that make us Smart&lt;/a&gt; book. None of these &lt;em&gt;things&lt;/em&gt; make us an expert&amp;#8230; merely an user.&lt;/p&gt;
&lt;p class="footnote" id="fn3"&gt;&lt;a href="#fnr3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; You can be a pretty smart programmer, but don&amp;#8217;t know a lot about the used programming language. To be a true expert you have to dive into the language itself and don&amp;#8217;t rely on an &lt;span class="caps"&gt;IDE&lt;/span&gt;.&lt;/p&gt;
&lt;p class="footnote" id="fn4"&gt;&lt;a href="#fnr4"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; There are many high quality editors out there. I like &lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt; most, but &lt;a href="http://www.gnu.org/software/emacs/"&gt;Emacs&lt;/a&gt;, &lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt; and &lt;a href="http://www.jedit.org/"&gt;JEdit&lt;/a&gt; are quite good too (and free, but keep the &lt;a href="http://twoday.tuwien.ac.at/ferrari/stories/19661/"&gt;learning curve&lt;/a&gt; in mind).&lt;/p&gt;
&lt;p class="footnote" id="fn5"&gt;&lt;a href="#fnr5"&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; See &lt;a href="http://www.apa.org/journals/features/psp7761121.pdf"&gt;Unskilled and Unaware of it&lt;/a&gt; (&lt;span class="caps"&gt;PDF&lt;/span&gt;, 500kb). Somewhat related: &lt;a href="http://media.pragprog.com/titles/mjwti/specialist.pdf"&gt;Being a specialist&lt;/a&gt; (&lt;span class="caps"&gt;PDF&lt;/span&gt;, 164kb).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/u_fPvSiBaUk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/texteditor_code_generation.html</feedburner:origLink></entry>
 
 <entry>
   <title>Ruby: future and delayed (lazy) variables</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/IXhCznPgvlI/rfuture.html" />
   <updated>2006-03-12T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/programming/rfuture</id>
   <content type="html">&lt;h2&gt;Future variables&lt;/h2&gt;
&lt;p&gt;Future variables are a very popular technique to implement dataflow execution. A future variable gets assigned with a (potentially lengthy) operation which will be executed in a separated thread. The assignment is therefore non-blocking.&lt;/p&gt;
&lt;p&gt;As soon as the variable gets read, it blocks if the calculation isn&amp;#8217;t ready, or it immediately returns the result.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve implemented that feature using some Ruby tricks, but the finest and most elegant solution would be in Lisp using it&amp;#8217;s unique macros.&lt;/p&gt;
&lt;p&gt;Anyways, here a quick example:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
x = RFuture.future do
   # some lengthy operation with an interesting result
end
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Now, that assignment doesn&amp;#8217;t block, and we could do some other things, later on we may want to know what the result of our operation is:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
puts x
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;This code &lt;strong&gt;could&lt;/strong&gt; block if the result isn&amp;#8217;t ready.&lt;/p&gt;
&lt;p&gt;As you can see, there is no special handling for reading the variable (meaning using adopting &lt;em&gt;future&lt;/em&gt; variables later on is quite easy).&lt;/p&gt;
&lt;p&gt;In the best case scenario the saved execution time is pretty high (compared to sequential processing):&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/rfuture.png" alt="" /&gt;&lt;/p&gt;
&lt;h2&gt;Delayed (lazy) variables&lt;/h2&gt;
&lt;p&gt;Another concept introduced in this library are &lt;em&gt;delayed&lt;/em&gt; or &lt;em&gt;lazy&lt;/em&gt; variables. These are variables which get assigned a operation which isn&amp;#8217;t executed until we really need the result. Seems pretty pointless, but it&amp;#8217;s used in some functional programming languages (like Hasekll).&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
x = RFuture.delay do
   # some operation with an interesting result we may need later on
end
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Again, reading the variable doesn&amp;#8217;t differ from usual variables:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
puts x
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;&lt;img src="http://blog.interlinked.org/static/images/rdelay.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blog.interlinked.org/static/files/RFuture.rb"&gt;Download the file here.&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/IXhCznPgvlI" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/rfuture.html</feedburner:origLink></entry>
 
 <entry>
   <title>Installing SQLite, Lighttpd, FastCGI and Ruby bindings on Mac OS X</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/14St89Wtfpk/ruby_sqlite_lighttpd.html" />
   <updated>2006-02-28T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/tutorials/ruby_sqlite_lighttpd</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve had a hard time installing &lt;a href="http://www.sqlite.org/"&gt;SQLite&lt;/a&gt;, &lt;a href="http://www.lighttpd.net/"&gt;Lighttpd&lt;/a&gt;, &lt;a href="http://www.fastcgi.com/"&gt;FastCGI&lt;/a&gt; together with &lt;a href="http://www.ruby-lang.org"&gt;Ruby&lt;/a&gt; bindings on OS X, so I thought I could share my experiences. Maybe someone has similar problems and finds some hints for solving them:&lt;/p&gt;
&lt;h2&gt;DarwinPorts&lt;/h2&gt;
&lt;p&gt;I used &lt;a href="http://www.darwinports.org/"&gt;DarwinPorts&lt;/a&gt; to install the software, don&amp;#8217;t forget to include the target directories to your path.&lt;/p&gt;
&lt;p&gt;For example I install the packages to /opt/local, so I&amp;#8217;ve included /opt/local/bin and /opt/local/sbin to may path.&lt;/p&gt;
&lt;p&gt;Example .profile:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
export PATH=/opt/local/bin:/opt/local/sbin:$PATH
&lt;/code&gt;
&lt;/pre&gt;
&lt;h2&gt;SQLite and Ruby&lt;/h2&gt;
&lt;p&gt;That was the hard part since my Ruby installation was not properly installed. The best way to install it is to remove ruby and it&amp;#8217;s dependencies first:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
port -uf uninstall ruby
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;After that install &lt;a href="http://www.swig.org/"&gt;&lt;span class="caps"&gt;SWIG&lt;/span&gt;&lt;/a&gt;, Ruby and &lt;a href="http://docs.rubygems.org/"&gt;Ruby Gems&lt;/a&gt; in that order:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
port install swig
port install ruby
port install rb-rubygems
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Mac OS X Tiger has SQLite3 pre-installed, if you choose to use SQLite 2 you have to install it from DarwinPorts:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
port install sqlite
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Now we&amp;#8217;re ready to install the &lt;a href="http://sqlite-ruby.rubyforge.org/"&gt;Ruby bindings for SQLite&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
gem install sqlite3-ruby
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;or for SQLite 2:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
gem install sqlite-ruby
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;My problem was that I had to remove Ruby, install swig and reinstall Ruby. If swig isn&amp;#8217;t installed gem can&amp;#8217;t compile the native bindings for Ruby and you&amp;#8217;ll get something like:&lt;/p&gt;
&lt;pre&gt;
sudo gem install sqlite
Attempting local installation of 'sqlite'
Local gem file not found: sqlite*.gem
Attempting remote installation of 'sqlite'
Building native extensions.  This could take a while...
ERROR:  While executing gem ... (RuntimeError)
    ERROR: Failed to build gem native extension.
Gem files will remain installed in /usr/lib/ruby/gems/1.8/gems/sqlite-2.0.1 for inspection.
  ruby extconf.rb install sqlite
checking for main() in -lsqlite... no
checking for sqlite.h... no
&lt;/pre&gt;
&lt;h2&gt;Lighttpd and FastCGI&lt;/h2&gt;
&lt;p&gt;Now we&amp;#8217;re ready to install Lighttpd and FastCGI:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
port install fcgi
port install pcre
port install lighttpd
gem install fcgi
&lt;/code&gt;
&lt;/pre&gt;
&lt;h2&gt;Now what?&lt;/h2&gt;
&lt;p&gt;Now you&amp;#8217;ve got a good starting point for other tutorials like:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://wiki.rubyonrails.org/rails/pages/HowToUseActiveRecordOutsideRails"&gt;How to use ActiveRecord outside Rails&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://whytheluckystiff.net/articles/aQuickGuideToSQLite.html"&gt;A Quick Guide to SQLite and Ruby&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;or simply start working with &lt;a href="http://webpy.org/"&gt;Web.py&lt;/a&gt;, &lt;a href="http://www.rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt;, &lt;a href="http://www.turbogears.org/"&gt;Turbo Gears&lt;/a&gt; or &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/14St89Wtfpk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/tutorials/ruby_sqlite_lighttpd.html</feedburner:origLink></entry>
 
 <entry>
   <title>Using your home Internet connection with your mobile phone and a Mac</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/yz6lRB29IlY/bt_sharing.html" />
   <updated>2005-11-16T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/mobile/bt_sharing</id>
   <content type="html">&lt;p&gt;After several hours of fooling around with my Nokia 6680 and some tools I&amp;#8217;ve finally succeeded! I&amp;#8217;m able to use my home Internet connection on my phone via Bluetooth! Now I&amp;#8217;m able to load my phone with tons of software, data and experiment with other nice applications like &lt;a href="http://www.google.com/glm"&gt;Google Maps&lt;/a&gt; without paying &lt;strong&gt;1.5 Euro per Megabyte&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Here a short step-by-step guide:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Setup a Serial Port on your Mac:
	&lt;ol&gt;
		&lt;li&gt;Open &lt;strong&gt;Bluetooth&lt;/strong&gt; in your System Preferences&lt;/li&gt;
		&lt;li&gt;Make sure your mobile is paired with your Mac (it should appear in the &lt;strong&gt;Devices&lt;/strong&gt; pane)&lt;/li&gt;
		&lt;li&gt;Go to the &lt;strong&gt;Sharing&lt;/strong&gt; pane. Here you should have a &lt;em&gt;Bluetooth-&lt;span class="caps"&gt;PDA&lt;/span&gt;-Sync&lt;/em&gt; click on it and enable &lt;em&gt;Require pairing for security&lt;/em&gt; and make shure that your Port &lt;strong&gt;Type&lt;/strong&gt; is set to &lt;em&gt;RS-232&lt;/em&gt;.&lt;br /&gt;
 If you don&amp;#8217;t have this port simply click on &lt;em&gt;Add Serial Port Service&lt;/em&gt; and configure it as described above.&lt;/li&gt;
		&lt;li&gt;It should look like this: &lt;img src="http://blog.interlinked.org/static/images/bluetooth_serial_port.png" alt="" /&gt;&lt;/li&gt;
		&lt;li&gt;Now run the &lt;em&gt;share&lt;/em&gt; script (at the end of this article) to associate a pppd and share your connection&lt;/li&gt;
	&lt;/ol&gt;&lt;/li&gt;
	&lt;li&gt;Download xans Version of &lt;a href="http://gnubox.dnsalias.org/gnubox/"&gt;GnuBox&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Install it on your mobile.
	&lt;ol&gt;
		&lt;li&gt;Create a new Access Point named &lt;strong&gt;Bt&lt;/strong&gt; on your mobile.&lt;/li&gt;
		&lt;li&gt;Set it up according to &lt;a href="http://gnubox.dnsalias.org/gnubox/#faqsupp6630"&gt;xans howto&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;Set your mobiles IP to 192.168.1.131 (or the IP you chose for it in the above script).&lt;/li&gt;
		&lt;li&gt;Setup the &lt;span class="caps"&gt;DNS&lt;/span&gt; IPs of your provider.&lt;/li&gt;
	&lt;/ol&gt;&lt;/li&gt;
	&lt;li&gt;Start the gnubox application
	&lt;ol&gt;
		&lt;li&gt;Ignore any error messages at the start&lt;/li&gt;
		&lt;li&gt;Choose Options&amp;#8594;Install&amp;#8594;create records&lt;/li&gt;
		&lt;li&gt;Choose Options&amp;#8594;Install&amp;#8594;copy settings from &lt;span class="caps"&gt;GPRS&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;Choose Options&amp;#8594;2box Bluetooth&amp;#8594;Serial port&lt;/li&gt;
		&lt;li&gt;Choose Options&amp;#8594;Debug&amp;#8594;Bring up IF&lt;/li&gt;
		&lt;li&gt;That&amp;#8217;s it! If you have any troubles, please refer to &lt;a href="http://gnubox.dnsalias.org/gnubox/trouble"&gt;xans troubleshooting guide&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;I&amp;#8217;ve used Opera to test the installation. You have to configure it &lt;strong&gt;exactly&lt;/strong&gt; like &lt;a href="http://gnubox.dnsalias.org/gnubox/opera_6630.png"&gt;here&lt;/a&gt; .&lt;/li&gt;
	&lt;/ol&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It&amp;#8217;s likely that some of this steps aren&amp;#8217;t necessary, but it&amp;#8217;s working for me.&lt;/p&gt;
&lt;h2&gt;Share&lt;/h2&gt;
&lt;p&gt;Here the script to &lt;strong&gt;share&lt;/strong&gt; your serial port with your AirPort. You may want to adapt the script according to your setup&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;IP Address (be sure to change it on both ends, mobile and Mac),&lt;/li&gt;
	&lt;li&gt;Serial Port name,&lt;/li&gt;
	&lt;li&gt;interface to share (for example the en1 interface is your AirPort and the en0 your Ethernet)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;
   &lt;code&gt;
 sudo /usr/sbin/pppd /dev/tty.Bluetooth-PDA-Sync 115200 \
   noauth local passive proxyarp \ 
   asyncmap 0 silent persist :192.168.1.131
 sudo /usr/sbin/sysctl -w net.inet.ip.forwarding=1
 sudo /usr/sbin/natd -same_ports -use_sockets -log -deny_incoming -interface en1
 sudo /sbin/ipfw add divert natd ip from any to any via en1
   &lt;/code&gt;
&lt;/pre&gt;
&lt;h2&gt;Unshare&lt;/h2&gt;
&lt;p&gt;To &lt;strong&gt;unshare&lt;/strong&gt; your port use this script:&lt;/p&gt;
&lt;pre&gt;
   &lt;code&gt;
 sudo /sbin/ipfw -f flush
 sudo killall natd
 sudo /usr/sbin/sysctl -w net.inet.ip.forwarding=0
 sudo killall pppd
   &lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;or simply restart your computer.&lt;/p&gt;
&lt;h2&gt;Further info&lt;/h2&gt;
&lt;p&gt;If you still have troubles try these ressources in order: &lt;a href="http://gnubox.dnsalias.org/gnubox/"&gt;xans howto&lt;/a&gt; &lt;a href="http://gnubox.dnsalias.org/gnubox/trouble.html"&gt;xans troubleshooting guide&lt;/a&gt; &lt;a href="http://www.symbianos.org/yabbse/index.php?board=2"&gt;support forum&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s also guide for &lt;a href="http://www.slamslash.com/nokia6600/"&gt;Macs and Nokia 6600 mobiles&lt;/a&gt; available.&lt;/p&gt;
&lt;p&gt;A very handy tool for debugging is the Bluetooth &lt;em&gt;PacketLogger&lt;/em&gt;, available if you&amp;#8217;ve XCode installed (take a look at /Developer/Applications/Utilities/Bluetooth).&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.technorati/tag/bluetooth" rel="tag"&gt;Bluetooth&lt;/a&gt; &lt;a href="http://www.technorati/tag/hack" rel="tag"&gt;Hack&lt;/a&gt; &lt;a href="http://www.technorati/tag/Series60" rel="tag"&gt;Series60&lt;/a&gt; &lt;a href="http://www.technorati/tag/Nokia" rel="tag"&gt;Nokia&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/yz6lRB29IlY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/mobile/bt_sharing.html</feedburner:origLink></entry>
 
 <entry>
   <title>Productivity and programming languages</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/SPnUA6VUe4w/productivity_and_programming_languages_2005-06-04.html" />
   <updated>2005-06-10T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/programming/productivity_and_programming_languages_2005-06-04</id>
   <content type="html">&lt;p&gt;We all know that programming languages affect productivity. For example writing a word processor in Assembler is much harder than writing it in C++. If seems natural to have a table with all available programming languages with their corresponding productivity value.&lt;/p&gt;
&lt;p&gt;The main problem is to compare these languages. A common method is counting the &amp;#8220;lines of code&amp;#8221; a programmer needs for a given program. But who is going to implement the same specification in hundreds of languages? So to make the test applicable we need a common concept for the comparison.&lt;/p&gt;
&lt;p&gt;This concept is called &amp;#8220;Function Point Analysis&amp;#8221;. This approach was introduced by &lt;span class="caps"&gt;IBM&lt;/span&gt; for exactly this task. Here you define function points (there are a lot of rules for doing that) and measure how many function points a programmer implements per month. More information about function points: &lt;a href="http://ourworld.compuserve.com/homepages/softcomp/fpfaq.htm"&gt;Function Point &lt;span class="caps"&gt;FAQ&lt;/span&gt;&lt;/a&gt; and &lt;a href="http://www.ifpug.com/fpafund.htm"&gt;Fundamentals of &lt;span class="caps"&gt;FPA&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the productivity measurement of programming languages we count the lines of code per function point.&lt;/p&gt;
&lt;p&gt;The languages are categorized into levels &amp;#8211; Assembler for example has level 1 with 320 lines of code per function point. A Macro Assembler has level 1.5 with 213 lines of code per function point etc&amp;#8230;&lt;/p&gt;
&lt;p&gt;Here an excerpt of &lt;a href="http://www.theadvisors.com/langcomparison.htm"&gt;this list&lt;/a&gt;:&lt;/p&gt;
&lt;table&gt;
 &lt;tr&gt;&lt;th&gt;Language&lt;/th&gt;&lt;th&gt;Level&lt;/th&gt;&lt;th&gt;LoC&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assembly (Basic)&lt;/td&gt;&lt;td&gt;1.00&lt;/td&gt;&lt;td&gt;320&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assembly (Macro)&lt;/td&gt;&lt;td&gt;1.50&lt;/td&gt;&lt;td&gt;213&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;&lt;td&gt;2.50&lt;/td&gt;&lt;td&gt;128&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C++&lt;/td&gt;&lt;td&gt;6.00&lt;/td&gt;&lt;td&gt;53&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Haskell&lt;/td&gt;&lt;td&gt;8.50&lt;/td&gt;&lt;td&gt;38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class="caps"&gt;JAVA&lt;/span&gt;&lt;/td&gt;&lt;td&gt;6.00&lt;/td&gt;&lt;td&gt;53&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class="caps"&gt;LISP&lt;/span&gt;&lt;/td&gt;&lt;td&gt;5.00&lt;/td&gt;&lt;td&gt;64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Objective-C&lt;/td&gt;&lt;td&gt;12.00&lt;/td&gt;&lt;td&gt;27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class="caps"&gt;SMALLTALK&lt;/span&gt; 80&lt;/td&gt;&lt;td&gt;15.00&lt;/td&gt;&lt;td&gt;21&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;A lot of languages are special languages &amp;#8211; like Excel with level 57. My guess is that a general purpose language is not able to go far beyond level 20.&lt;/p&gt;
&lt;p&gt;Another table from &lt;a href="http://www.dacs.dtic.mil/techs/baselines/productivity.html"&gt;here&lt;/a&gt; shows this:&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;
	&lt;td&gt;&lt;b&gt;Language&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;LoC&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td&gt;Assembler&lt;/td&gt;&lt;td&gt;320&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td&gt;Macro Assembler&lt;/td&gt;&lt;td&gt;213&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td&gt;C&lt;/td&gt;&lt;td&gt;150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td&gt;Lisp&lt;/td&gt;&lt;td&gt;64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td&gt;Basic&lt;/td&gt;&lt;td&gt;64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td&gt;Objective &amp;#8211; C&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td&gt;Smalltalk&lt;/td&gt;&lt;td&gt;21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td&gt;Query Languages&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td&gt;Spreadsheet Languages&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The values are the same or at least nearly the same for the languages (maybe they came from the same source?)&lt;/p&gt;
&lt;p&gt;I would like to see a JavaScript, Ruby and Python included in these tables, but unfortunately I couldn&amp;#8217;t find anything for these languages. I think JavaScript is no better than 10, Python and Ruby are together with Perl around 15, maybe Ruby has the highest level of these languages (Comments?).&lt;/p&gt;
&lt;p&gt;The higher the language level the easier it is to read and change such a program. There is &amp;#8211; of course &amp;#8211; a trade off: the more code you write (for example in assembler) the more optimizations are possible. With increasing processor speed, and advanced algorithms this argument is getting more and more obsolete.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/SPnUA6VUe4w" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/productivity_and_programming_languages_2005-06-04.html</feedburner:origLink></entry>
 
 <entry>
   <title>REST Web-services</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/H_mFCO4fu9I/rest_web_services.html" />
   <updated>2005-04-10T00:00:00+02:00</updated>
   <id>http://blog.interlinked.org/misc/rest_web_services</id>
   <content type="html">&lt;p&gt;If people talk of &amp;#8220;Web-Services&amp;#8221;, they often mean &lt;a href="http://www.w3.org/TR/2003/REC-soap12-part1-20030624/"&gt;&lt;span class="caps"&gt;SOAP&lt;/span&gt;&lt;/a&gt; as maintained by the &lt;a href="http://www.w3.org/"&gt;W3C&lt;/a&gt;. But &lt;span class="caps"&gt;SOAP&lt;/span&gt; isn&amp;#8217;t everything. In fact &lt;span class="caps"&gt;SOAP&lt;/span&gt; &lt;b&gt;was&lt;/b&gt; a basically a &lt;span class="caps"&gt;RPC&lt;/span&gt; (Remote Procedure Call) protocoll over &lt;span class="caps"&gt;HTTP&lt;/span&gt; (therefore the name Simple Object Access Protocoll). Since W3C took over &lt;span class="caps"&gt;SOAP&lt;/span&gt; (from Microsoft and later &lt;span class="caps"&gt;IBM&lt;/span&gt;) it has been extended into more general directions.&lt;/p&gt;
&lt;p&gt;With &lt;span class="caps"&gt;REST&lt;/span&gt; (Representational State Transfer) similar applications can be written. &lt;span class="caps"&gt;REST&lt;/span&gt; itself is only an architectural style (defining how you &lt;b&gt;should&lt;/b&gt; design your application). &lt;span class="caps"&gt;REST&lt;/span&gt; was initiated by the &lt;span class="caps"&gt;IETF&lt;/span&gt; as the basic model for the modern Web. &lt;span class="caps"&gt;HTTP&lt;/span&gt; 1.1 was designed using &lt;span class="caps"&gt;REST&lt;/span&gt; as tool for discovering unproper features etc&amp;#8230; .&lt;/p&gt;
&lt;h2&gt;What is the essence of &lt;span class="caps"&gt;REST&lt;/span&gt;?&lt;/h2&gt;
&lt;p&gt;&lt;span class="caps"&gt;REST&lt;/span&gt; sees the Web as a collection of &lt;i&gt;resources&lt;/i&gt; connected to a common network. Each resource has a set of associated methods (&lt;span class="caps"&gt;PUT&lt;/span&gt;, &lt;span class="caps"&gt;GET&lt;/span&gt;, &lt;span class="caps"&gt;POST&lt;/span&gt;, &lt;span class="caps"&gt;DELETE&lt;/span&gt;) to operate on them. &lt;span class="caps"&gt;SOAP&lt;/span&gt; on the other hand has &lt;i&gt;services&lt;/i&gt; with definable methods (like getCustomerRecord, setCPUHeat etc&amp;#8230;).&lt;/p&gt;
&lt;p&gt;Since &lt;span class="caps"&gt;REST&lt;/span&gt; heavily depends (or defines) on existing standards existing software can easily be used with it. For example firewall administrators can block writing methods (&lt;span class="caps"&gt;DELETE&lt;/span&gt;, &lt;span class="caps"&gt;PUT&lt;/span&gt;, &lt;span class="caps"&gt;POST&lt;/span&gt;) on some resources, or internet caches are able to store resources requested by &lt;span class="caps"&gt;GET&lt;/span&gt;. &lt;span class="caps"&gt;SOAP&lt;/span&gt; uses &lt;span class="caps"&gt;POST&lt;/span&gt; (non-cacheable) to transfer the data between the client and the server. Using &lt;span class="caps"&gt;SOAP&lt;/span&gt; a firewall administrator has no chance to control access to his resources &amp;#8211; he can allow or disallow &lt;span class="caps"&gt;SOAP&lt;/span&gt; (meaning &lt;span class="caps"&gt;HTTP&lt;/span&gt;). &lt;span class="caps"&gt;SOAP&lt;/span&gt; applications have to manager their own security.&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;REST&lt;/span&gt;/&lt;span class="caps"&gt;SOAP&lt;/span&gt; debate is often compared to pre-&lt;span class="caps"&gt;SQL&lt;/span&gt; eras. Think of a database  providing &amp;#8220;getCustomerRecord&amp;#8221; and &amp;#8220;setCPUHeat&amp;#8221; commands instead of general &lt;span class="caps"&gt;SELECT&lt;/span&gt; and &lt;span class="caps"&gt;UPDATE&lt;/span&gt; statements on resources like &amp;#8220;Customer&amp;#8221; and &amp;#8220;&lt;span class="caps"&gt;CPU&lt;/span&gt;&amp;#8221;. The same applies to &lt;span class="caps"&gt;REST&lt;/span&gt; &amp;#8211; here we have general methods, with &lt;span class="caps"&gt;SOAP&lt;/span&gt; we have specialized interfaces.&lt;/p&gt;
&lt;h2&gt;Why &lt;span class="caps"&gt;SOAP&lt;/span&gt; if &lt;span class="caps"&gt;REST&lt;/span&gt; is so good?&lt;/h2&gt;
&lt;p&gt;&lt;span class="caps"&gt;SOAP&lt;/span&gt; is a product (at least you can make products from the &lt;span class="caps"&gt;SOAP&lt;/span&gt; specification) &amp;#8211; &lt;span class="caps"&gt;REST&lt;/span&gt; is &amp;#8220;only&amp;#8221; an architectural style. Guess with which one companies can make money? &lt;span class="caps"&gt;REST&lt;/span&gt; of course has it&amp;#8217;s drawbacks too, for example you cannot buy libraries to ease some task&amp;#8230; . &lt;span class="caps"&gt;REST&lt;/span&gt; isn&amp;#8217;t widely known/accepted and few companies provide explicit support. Amazon calls it&amp;#8217;s &lt;span class="caps"&gt;XML&lt;/span&gt; over &lt;span class="caps"&gt;HTTP&lt;/span&gt; a &lt;span class="caps"&gt;REST&lt;/span&gt; interface, del.icio.us and flickr have &lt;span class="caps"&gt;REST&lt;/span&gt; interfaces too (usually &lt;span class="caps"&gt;XML&lt;/span&gt; over &lt;span class="caps"&gt;HTTP&lt;/span&gt;). The biggest drawback of &lt;span class="caps"&gt;REST&lt;/span&gt; is the lack of a description language &amp;#8211; &lt;span class="caps"&gt;SOAP&lt;/span&gt; has a very powerful one with &lt;span class="caps"&gt;WSDL&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Want a more in-depth treatment? &lt;a href="http://blog.interlinked.org/static/files/rest.pdf"&gt;&lt;span class="caps"&gt;REST&lt;/span&gt; article in &lt;span class="caps"&gt;PDF&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/H_mFCO4fu9I" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/misc/rest_web_services.html</feedburner:origLink></entry>
 
 <entry>
   <title>Lessons of game design</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/VW5IB5zPbTQ/lessons_of_game_design.html" />
   <updated>2005-03-10T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/programming/lessons_of_game_design</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re searching &lt;span class="caps"&gt;UML&lt;/span&gt;, Design Patterns or suchlike, you&amp;#8217;re wrong here &amp;#8211; this time I&amp;#8217;ll try to cover some principles of puzzle design to general software from the point of the user:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.scottkim.com/"&gt;Scott Kim&lt;/a&gt;, a well known Puzzle creator has written a great paper on Puzzle design called &amp;#8220;The Puzzlemaker&amp;#8217;s Survival Kit&amp;#8221; (sorry, no link available).&lt;/p&gt;
&lt;p&gt;He goes through principles, case studies and the design process of puzzle and game design. Some of these guides can (&lt;span class="caps"&gt;IMHO&lt;/span&gt;) applied to software design in general.&lt;/p&gt;
&lt;p&gt;How? I think, puzzles in games and features in general software aren&amp;#8217;t that different. Here the first principle of puzzle design written by Scott Kim:&lt;/p&gt;
&lt;p&gt;He also writes:&lt;/p&gt;
&lt;p&gt;bq.A puzzle is a problem that is fun to solve!&lt;br /&gt;
What makes puzzles different from problems is that they are fun to solve. A good puzzle is guaranteed to have a solution that is neither too easy nor too hard to find.&lt;/p&gt;
&lt;p&gt;If we map &lt;i&gt;puzzle&lt;/i&gt; to &lt;i&gt;real world problem I want/have to solve&lt;/i&gt; we should design our software to allow this as easy as possible and powerful as needed. So, our software should enable the user to solve a problem with joy!&lt;/p&gt;
&lt;p&gt;I wouldn&amp;#8217;t limit &amp;#8220;fun&amp;#8221; to games &amp;#8211; I think we could build software that every problem is fun to solve because the software helps us and doesn&amp;#8217;t step in the way. It depends only on our imagination and our willing to invest &lt;b&gt;a lot of time&lt;/b&gt; to build software that is fun to use. (Although game puzzles may be &lt;i&gt;more&lt;/i&gt; fun to solve, but not as rewarding).&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&amp;#8230;neither too easy nor too hard&amp;#8230;&lt;/i&gt; is another interesting phrase. Doesn&amp;#8217;t that map directly to the &lt;b&gt;power&lt;/b&gt; of any feature included into a piece of software? Conclusion: don&amp;#8217;t treat your users as complete dumbs, design your features &lt;b&gt;right&lt;/b&gt; &amp;#8211; not too complex, but with enough power to perform a specific &lt;b&gt;kind&lt;/b&gt; of task.&lt;/p&gt;
&lt;p&gt;Scott Kim explains how to construct puzzles in games, let&amp;#8217;s see if we can map these to software in general.&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;&lt;br /&gt;
Think small.&lt;br /&gt;
&lt;/cite&gt;&lt;/p&gt;
&lt;p&gt;Interesting, huh? &lt;i&gt;Think small&lt;/i&gt; as advice! Isn&amp;#8217;t that the same as Apples &lt;i&gt;Think different&lt;/i&gt; &amp;#8211; just take the iPod Shuffle or the Mac Mini? A lot of people try to get more and more features into a piece of software (Think big), but these systems tend to be overly complex and unusable (at least for me).&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;&lt;br /&gt;
See how far you can get with the smallest number of features.&lt;br /&gt;
&lt;/cite&gt;&lt;/p&gt;
&lt;p&gt;This is one of the most thrilling and adorable advices I&amp;#8217;ve ever read! Don&amp;#8217;t build battalions of special cases. Extract, refine and rewrite until you&amp;#8217;ve got a truly elegant solution for the problems you want to solve. The web, meaning &lt;span class="caps"&gt;HTTP&lt;/span&gt;, follows exactly this advice. They striped out every special case and build a solid foundation for thousands of web applications by not disturbing or limiting the possibilities. See &lt;a href="http://www.w3.org/DesignIssues/Principles.html"&gt;Axioms of Web architecture&lt;/a&gt; for more.&lt;/p&gt;
&lt;p&gt;Many, if not all, of the brightest minds of history gave this advice &amp;#8211; starting from Da Vinci &lt;i&gt;Simplicity is the ultimate sophistication.&lt;/i&gt;, Hoare &lt;i&gt;The price of reliability is the pursuit of the utmost simplicity. It is a price which the very rich find most hard to pay.&lt;/i&gt;, Dijkstra &lt;i&gt;Simplicity and elegance are unpopular because thy require hard work and discipline to achieve and education to be appreciated.&lt;/i&gt; or &lt;i&gt;Simplicity is prerequisite for reliability.&lt;/i&gt;&amp;#8230; .&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;&lt;br /&gt;
Start with a tutorial.&lt;br /&gt;
&lt;/cite&gt;&lt;/p&gt;
&lt;p&gt;Definitively a game design advice, or not? &lt;a href="http://www.eclipse.org"&gt;Eclipse&lt;/a&gt;, &lt;a href="http://www.gmail.com"&gt;GMail&lt;/a&gt; and many more start with a tutorial &amp;#8211; maybe we should think of including a &lt;b&gt;quick&lt;/b&gt; and simple introduction into any given piece of software?&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;&lt;br /&gt;
Make puzzles easy to author.&lt;br /&gt;
&amp;#8230;&lt;br /&gt;
Construction puzzles need to be as easy and fun to author as they are &lt;br /&gt;
to solve.&lt;br /&gt;
&amp;#8230;&lt;br /&gt;
&lt;/cite&gt;&lt;/p&gt;
&lt;p&gt;This is a very underestimated advice in general software. Why do we think that we are the great masterminds and know every single case our users want to do with the software? There is no possible way for doing that with any given real world problem!&lt;/p&gt;
&lt;p&gt;Open up your software and let users create features the need through an &lt;span class="caps"&gt;API&lt;/span&gt;, scripting capabilities or whatever.&lt;br /&gt;
Design these interfaces so, that no existing code has to be read to use the &lt;span class="caps"&gt;API&lt;/span&gt;, Interface or Scripting capabilities. Make it &lt;b&gt;easy&lt;/b&gt; to build new functionality and don&amp;#8217;t even try to lock in the user!&lt;/p&gt;
&lt;p&gt;Even Microsoft allows users to build their own little programs within their office suite.&lt;/p&gt;
&lt;p&gt;Another big advantage: You might use that feature yourself to build new features and customizations&amp;#8230; .&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;&lt;br /&gt;
Simplification!&lt;br /&gt;
&lt;/cite&gt;&lt;/p&gt;
&lt;p&gt;Do it! Any feature you find &amp;#8220;hard to use&amp;#8221; is for the user simply unusable &amp;#8211; your user doesn&amp;#8217;t invest month or years learning (like you building) the software!&lt;/p&gt;
&lt;p&gt;User interfaces which you &amp;#8211; as the creator &amp;#8211; find &amp;#8220;super easy&amp;#8221; are usually &amp;#8220;just right&amp;#8221; for your users.&lt;/p&gt;
&lt;p&gt;[I&amp;#8217;ve written this in a rush, so please excuse some weird phrases and formulations.]&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/VW5IB5zPbTQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/lessons_of_game_design.html</feedburner:origLink></entry>
 
 <entry>
   <title>Battery lifetime</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/tQtq75IsSm8/battery_lifetime.html" />
   <updated>2005-02-10T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/misc/battery_lifetime</id>
   <content type="html">&lt;p&gt;Rechargeable lithium-ion batteries are very common in gadgets like laptops, PDAs and cell phones, unfortunately these are very expensive. I had to replace my Sony battery for 250 Euro(!) &amp;#8211; well I bought a cheaper clone for 100 Euro, but it has its drawbacks (at the beginning it worked for 3 hours, now for about one&amp;#8230;).&lt;/p&gt;
&lt;p&gt;So it pays if you keep your current battery up and running as long as possible. Here are a few facts I&amp;#8217;ve collected over the last few months:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Lithium-ion batteries can be recharged whenever convenient, there is no memory effect&lt;/li&gt;
	&lt;li&gt;A new battery should be charged and discharged fully for the first three cycles (initial conditioning)&lt;/li&gt;
	&lt;li&gt;Keep the electrons moving (discharge/recharge the battery at least once every month)&lt;/li&gt;
	&lt;li&gt;Don&amp;#8217;t keep your device plugged in all the time (this is &lt;b&gt;very&lt;/b&gt; bad for the battery)&lt;/li&gt;
	&lt;li&gt;Keep the working temperature in mind (22°C is best for most devices)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I put my notebook battery out if I&amp;#8217;m working plugged in for a longer time.&lt;/p&gt;
&lt;p&gt;Notebook Li-Ion batteries have a typical lifetime of about three years, but this depends on how you use it. A friend of mine uses his notebook on a daily basis (on battery) and his battery works for about four years now &amp;#8211; I&amp;#8217;ve used my notebook occasionally (mostly plugged in) and the battery had to be replaced after 2.5 years&amp;#8230; .&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve read some posts on bulletin boards telling me to put my battery into the refrigerator &amp;#8211; these procedure should repair some structure and the battery should work like a new one. Well I&amp;#8217;ve tried it with my old battery, but it didn&amp;#8217;t work :-).&lt;/p&gt;
&lt;p&gt;Broken batteries usually provide their full power but only on very low power consumption, for example my broken laptop battery could power my cell phone for days (weeks?) because it consumes much less power than the laptop.&lt;/p&gt;
&lt;p&gt;More resources:&lt;br /&gt;
&lt;a href="http://www.apple.com/batteries/"&gt;Apple&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.cellpower.com/battery_tips.cfm"&gt;Cellpower&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Well &amp;#8211; I&amp;#8217;m after all a software guy, so the electronic stuff written here should be used with caution :-).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/tQtq75IsSm8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/misc/battery_lifetime.html</feedburner:origLink></entry>
 
 <entry>
   <title>Repetition is the root of all evil</title>
   <link href="http://feedproxy.google.com/~r/IMHO/~3/Z_0SLvrJ_b4/repetition_is_the_root_of_all_evil.html" />
   <updated>2005-01-10T00:00:00+01:00</updated>
   <id>http://blog.interlinked.org/programming/repetition_is_the_root_of_all_evil</id>
   <content type="html">&lt;p&gt;Yes, repetition is the root of all evil. Knuth (or was it Hoare?) said &amp;#8220;Premature optimization is the root of all evil&amp;#8221;, but I think it&amp;#8217;s repetition. In fact repetition is often used to provide better performance (eg loop unrolling to suit your CPUs pipeline or the good old &lt;a href="http://www.jargon.net/jargonfile/d/Duffsdevice.html"&gt;Duff&amp;#8217;s device&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m talking about repetition in software &amp;#8211; the typical copy and paste fault. Every programming book I&amp;#8217;ve read so far deals in one or the other way with reducing repetition.&lt;/p&gt;
&lt;p&gt;Think of patterns &amp;#8211; each pattern tries to reduce the amount of code written by providing professional reuse mechanisms.&lt;br /&gt;
- Factory tries to concentrate the code for creating objects on one place,&lt;br /&gt;
- Strategy tries to supply a mechanism to traverse through interconnected objects,&lt;br /&gt;
- Facade lets an existing piece of code hide behind another interface.&lt;br /&gt;
- Singleton seems to be an exception because it reduces not the code replication rather the data replication.&lt;/p&gt;
&lt;p&gt;In Test Driven Development the rules are simple:&lt;br /&gt;
- write a test (red bar)&lt;br /&gt;
- fake to get the bar green (unit tests are ok, when the &amp;#8220;bar&amp;#8221; is green)&lt;br /&gt;
- clean up and &lt;b&gt;remove replications&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Every programming language which doesn&amp;#8217;t provide good facilities to reduce replication should be considered harmful! All functional languages have facilities to pass around functions, Python and Ruby introduced similar techniques, Java&amp;#8230; well no, but you can simulate such a behavior with enormous amount of code (I don&amp;#8217;t know C#, but I guess Anders Hejlsberg introduced something similar).&lt;/p&gt;
&lt;p&gt;Whenever you look at a program or you&amp;#8217;re writing one and you discover some kind of repetition: Remove it! Kill it! Destroy it&amp;#8230; whatever but &lt;b&gt;get rid of it&lt;/b&gt;!&lt;/p&gt;
&lt;p&gt;Each time I introduced some sort of repetition and had to fix a bug in there, I forgot to fix the replica&amp;#8230;&lt;/p&gt;
&lt;p&gt;Now, what should we do to reduce replication? Sometimes it&amp;#8217;s a bit hard to remove the replication. In the eighties the keyword was &lt;b&gt;subclassing&lt;/b&gt;. Today subclassing is considered a performance killer and is sometimes referred to as hardwired code. &lt;br /&gt;
Now we have patterns &amp;#8211; those magic constructs made by object gurus. I doubt that too many people do some kind of &amp;#8220;pattern driven&amp;#8221; design &amp;#8211; those systems would get utterly complex and even harder to maintain than systems with a few repetitions.&lt;br /&gt;
So, whenever you encounter a repetition just remove it as best as you can, don&amp;#8217;t hack! Think of a clean lean design and write some tests before changing something (just to be sure you didn&amp;#8217;t break something).&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s one of Extreme Programming&amp;#8217;s weaknesses: there is no master plan the whole team adheres. Each pair of programmers implements their user stories and doesn&amp;#8217;t know what the others do (unless the pairs are changed very (very) frequently). &lt;i&gt;[Extreme Programming isn&amp;#8217;t written in stone, every team can adopt it to it&amp;#8217;s own needs &amp;#8211; so maybe there are some who indeed have such a master-plan]&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;On the other hand repetition helps me to remember things, therefore:&lt;br /&gt;
Remove repetition in your software (and your friends software) as soon as you discover it!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/IMHO/~4/Z_0SLvrJ_b4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://blog.interlinked.org/programming/repetition_is_the_root_of_all_evil.html</feedburner:origLink></entry>
 
 
</feed>
