<?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><![CDATA[Balint Erdi]]></title>
  
  <link href="http://balinterdi.com/" />
  <updated>2013-02-08T14:25:46+01:00</updated>
  <id>http://balinterdi.com/</id>
  <author>
    <name><![CDATA[Balint Erdi]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/codigoergosum" /><feedburner:info uri="codigoergosum" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title type="html"><![CDATA[Lessons learned from solving 4Clojure problems]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/XMy5NhHPt1A/lessons-learned-from-solving-4clojure-problems.html" />
    <updated>2012-12-29T14:55:00+01:00</updated>
    <id>http://balinterdi.com/2012/12/29/lessons-learned-from-solving-4clojure-problems</id>
    <content type="html">&lt;p&gt;A few days ago I completed the last problem on the &lt;a href="http://4clojure.com"&gt;4Clojure&lt;/a&gt; site. If you
want to learn Clojure, solving these problems is a great way to do it. Several
of its features -that I&amp;#8217;ll highlight below- make it a great learning tool. Other
features probably arise from &lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt; being a
(pragmatic) functional programming language. Coming from mostly an OO background
these were also new to me and thus deserve their own paragraph.&lt;/p&gt;

&lt;p&gt;I hope that after reading through the list you&amp;#8217;ll end up being persuaded of the
merits and want to solve (some of) the problems yourself. If you do, please let
me know how it went and what you learned from it.&lt;/p&gt;

&lt;p&gt;If you really get stuck, there is a &lt;a href="https://groups.google.com/forum/?fromgroups#!forum/4clojure"&gt;Google group dedicated to the 4Clojure
problems&lt;/a&gt;. You can also leave a comment here so I can help or go directly to
check &lt;a href="https://gist.github.com/raw/4008944/9c0577566b9a87e8db03332bf71b6d0b1140748e/4clojure.clj"&gt;my solutions&lt;/a&gt;. Let&amp;#8217;s jump in.&lt;/p&gt;

&lt;h2&gt;Why is 4Clojure a great learning tool?&lt;/h2&gt;

&lt;h3&gt;Looking at others&amp;#8217; solutions&lt;/h3&gt;

&lt;p&gt;After solving a problem, you can check how the users you follow solved it.
That&amp;#8217;s arguably the most important feature when it comes to learning since it
is essentially a code reading exercise when the functionality of the code is
well-known (since it solves the same problem you&amp;#8217;ve solved) and the authors are
probably more proficient.&lt;/p&gt;

&lt;p&gt;On several occasions I saw solutions that were both more concise and clearer
than mine (especially when tackling a hard problem). Dealing with the
inferiority complex on the very short term is dwarved by how much wisdom you
gain from these. For what it&amp;#8217;s worth, the users I learned most from are
&lt;a href="http://www.4clojure.com/user/hypirion"&gt;hypirion&lt;/a&gt;,
&lt;a href="http://www.4clojure.com/user/jafingerhut"&gt;jafingerhut&lt;/a&gt; and
&lt;a href="http://www.4clojure.com/user/chouser"&gt;chouser&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;(If you&amp;#8217;d like to follow me, I&amp;#8217;m &lt;a href="http://www.4clojure.com/user/balint"&gt;balint&lt;/a&gt;
there.)&lt;/p&gt;

&lt;h3&gt;Executable, well thought-out test cases&lt;/h3&gt;

&lt;p&gt;To submit your solution, you paste your code into a textbox and click a button.
The test cases, which are visible, are then checked one by one. If all the
lamps become green, your solution is accepted. If not, you get an error
message and have to try again.&lt;/p&gt;

&lt;p&gt;This method has several advantages. First of all, it eliminates the imprecisions
you might have had after reading the description of the problem. Second, it
gives you a set of examples to work against. Third, they force you to think
deeper about the problem since they are constructed to reject a partial
solution.&lt;/p&gt;

&lt;h3&gt;Timeouts&lt;/h3&gt;

&lt;p&gt;Your solution can be functional and pass all the test cases but if it does not
finish in a certain time, it will get rejected. I bumped into this on several
occasions. Most of the time it was because I came up with the brute force
solution to a hard problem and hoped I&amp;#8217;d get away with it. In other cases it was
because of a technical issue, like allocating too much memory.&lt;/p&gt;

&lt;p&gt;In the first case, it made me think again about the problem (see Hammock-Driven
Development) and come up with a more ingenious solution. In the second case, I
learned something about a technical aspect of the language. In both cases, I
grew a bit wiser about optimization -which is a &amp;#8220;real-world&amp;#8221; coding skill- so
I&amp;#8217;m happy the authors of 4clojure chose to implement this constraint.&lt;/p&gt;

&lt;h2&gt;What does one learn about (functional) programming?&lt;/h2&gt;

&lt;h3&gt;Hammock-Driven Development&lt;/h3&gt;

&lt;p&gt;Also known as “step-away from the computer to solve hard problems”, Hammock-Driven
Development is a term coined by Rich Hickey, the creator of Clojure, in a &lt;a href="http://www.youtube.com/watch?v=f84n5oFoZBc"&gt;keynote
speech&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Apparently ridiculing Test Driven Development (TDD), HDD holds that the most
important activity to solve a hard problem is to think deeply about it without
any distractions. Most of the time sitting in front of the computer is a
distraction in itself since it begs to be typed on and prevents actual deep thinking
to happen.&lt;/p&gt;

&lt;p&gt;This one is really hard to get used to because whenever we write code we feel like
we&amp;#8217;re getting closer to a solution. Thinking, on the other hand, does not
provide any tangible output.&lt;/p&gt;

&lt;p&gt;However, HDD has rung ever more true with me as I progressed. When tackling hard
problems, I tended to think about them for some time and then started to type in
actual code. The problem was, when I felt that the solution became convoluted I
did not go back to the proverbial hammock but carried on with the implementation.
Most of the time it either turned out to be a dead-end or a solution I&amp;#8217;d much
better hide.&lt;/p&gt;

&lt;p&gt;Even more importantly, a cleaner solution is one that is easier for
others to understand. Since code is mainly for others to read and occasionally
for computers to execute, more thinking up-front results in less time spent
developing and maintaining the code down the line.&lt;/p&gt;

&lt;h3&gt;The REPL is a powerful developer tool&lt;/h3&gt;

&lt;p&gt;The power of the REPL is one those realizations most of us coming from OO will
come to. Since FP languages have &lt;a href="http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey"&gt;very little state&lt;/a&gt; and side-effects and
thus a lot of idempotency, trying things at the REPL is taken to the next
level. You launch a REPL once and then copy-paste the building blocks of your
solution between your editor and the REPL (and there are &lt;a href="https://github.com/jpalardy/vim-slime"&gt;better&lt;/a&gt;
&lt;a href="https://github.com/kingtim/nrepl.el"&gt;solutions&lt;/a&gt; then copy-pasting).&lt;/p&gt;

&lt;h3&gt;Use higher level functions&lt;/h3&gt;

&lt;p&gt;FP languages strive to have a small set of data structures and a high number of
functions that operate on them. Clojure is no exception. Though it&amp;#8217;s not hard to
assemble the higher-level function you need yourself, in the majority of cases,
it&amp;#8217;s just extra work: it&amp;#8217;s probably already defined in the core.&lt;/p&gt;

&lt;p&gt;This is something that I learned by reading others&amp;#8217; solutions and learning
about awesome functions (&lt;a href="http://clojuredocs.org/clojure_core/clojure.core/frequencies"&gt;frequencies&lt;/a&gt;, &lt;a href="http://clojuredocs.org/clojure_core/clojure.core/merge-with"&gt;merge-with&lt;/a&gt;, &lt;a href="http://clojuredocs.org/clojure_core/clojure.core/condp"&gt;condp&lt;/a&gt; come to mind).
After a while I looked up the high-level function myself from &lt;a href="http://clojure.org/cheatsheet"&gt;the
cheatsheet&lt;/a&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=XMy5NhHPt1A:20E2tSF_kYk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=XMy5NhHPt1A:20E2tSF_kYk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=XMy5NhHPt1A:20E2tSF_kYk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=XMy5NhHPt1A:20E2tSF_kYk:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/XMy5NhHPt1A" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2012/12/29/lessons-learned-from-solving-4clojure-problems.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Switch to Command Line Vim on iTerm]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/hd3yVBueyrg/switch-to-command-line-vim-on-iterm.html" />
    <updated>2012-03-30T12:04:00+02:00</updated>
    <id>http://balinterdi.com/2012/03/30/switch-to-command-line-vim-on-iterm</id>
    <content type="html">&lt;p&gt;Switching between applications is more of a mental context switch than just switching between the panes in the same window. Or at least that&amp;#8217;s what I told myself when I decided I switch from using macvim to the simple command line version. It also brings me pretty close to using tmux which I would primarily use to send commands between panes. Most of the posts about using tmux only briefly touch on switching to command line vim so I thought I&amp;#8217;d fill in the gap somewhat.&lt;/p&gt;

&lt;p&gt;I use iTerm2 on a MacBook Pro and run 10.6.8 (Snow Leopard), although I think it should run
fine under Lion, too.&lt;/p&gt;

&lt;p&gt;First, you&amp;#8217;ll have to install a fairly recent vim. Homebrew has a policy of not having packages which the operating system already provides, but fortunately there is a &lt;a href="https://github.com/Homebrew/homebrew-dupes"&gt;homebrew-dupes&lt;/a&gt; repository that has vim:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;$ brew install --HEAD https://raw.github.com/Homebrew/homebrew-dupes/master/vim.rb&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This will configure, make and install vim.&lt;/p&gt;

&lt;p&gt;Next, I looked for a theme that looks good on both a light and a dark background and has iTerm support (a colorscheme for the terminal emulator). I&amp;#8217;ve found &lt;a href="http://ethanschoonover.com/solarized"&gt;Ethan Schoonover&amp;#8217;s solarized theme&lt;/a&gt; really cool. Just follow the steps in the &lt;a href="https://github.com/altercation/ethanschoonover.com/tree/master/projects/solarized"&gt;README of the repository&lt;/a&gt; to download both the vim and the iTerm colorscheme.&lt;/p&gt;

&lt;p&gt;To install the iTerm colorscheme, go to Preferences -&gt; Profiles to select your
profile and then click the Colors tab. There is a &amp;#8220;Load Presets&amp;#8221; dropdown from
which you have to choose Import and find the solarized itermcolors file.&lt;/p&gt;

&lt;p&gt;To use the vim colorscheme you have to add the colors file to somewhere where
vim finds it. There are many ways to do this, so check out the &lt;a href="https://github.com/altercation/ethanschoonover.com/tree/master/projects/solarized"&gt;README&lt;/a&gt; to
find the method that suits you.&lt;/p&gt;

&lt;p&gt;Once, done you have to set the colorscheme in your vimrc:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;colorscheme solarized&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;(vim finds out the appropriate background automatically, so you don&amp;#8217;t have to
explicitly set the background)&lt;/p&gt;

&lt;p&gt;I was all set up and most things worked just like in the GUI version. One thing that bugged me was that my cursor keys stopped working. I don&amp;#8217;t use them for moving and text input but I do for cycling in the command history or flipping between file matches for Command-T. It took me a while to find out that iTerm sends a wrong escape sequence for the arrow keys. I could fix that by selecting another set of key presets for the terminal&amp;#8217;s profile. In iTerm, go to Preferences -&gt; Profiles and select your profile. Select Keys, then Load Preset and select xTerm with Numeric Keypad.&lt;/p&gt;

&lt;p&gt;There is one more trick I find handy. If you set&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;set clipboard=unnamed&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;in your config, then anything you copy from vim by the usual vim commands (y, d, x, etc.) will be available on your system clipboard and thus pastable.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=hd3yVBueyrg:I6g14488mhA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=hd3yVBueyrg:I6g14488mhA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=hd3yVBueyrg:I6g14488mhA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=hd3yVBueyrg:I6g14488mhA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/hd3yVBueyrg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2012/03/30/switch-to-command-line-vim-on-iterm.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[An Annotated Assortment on Mockist Testing]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/V7nPh5Y07-o/an-annotated-assortment-on-mockist-testing.html" />
    <updated>2011-11-30T21:30:00+01:00</updated>
    <id>http://balinterdi.com/2011/11/30/an-annotated-assortment-on-mockist-testing</id>
    <content type="html">&lt;p&gt;Most of us read blog posts every day. We read them, take an idea out of
them and then, most of the time, forget about them. Some of them are stashed
away in the back of our minds, ready to jump out if we face a related
problem.&lt;/p&gt;

&lt;p&gt;A precious few of them, however, we keep thinking back to without a specific
reason.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve bitten by the &amp;#8220;mockist&amp;#8221; testing bug when I read &lt;a href="http://jamesgolick.com/2010/3/14/crazy-heretical-and-awesome-the-way-i-write-rails-apps.html"&gt;this one&lt;/a&gt; a while ago. It expresses a contrarian opinion
about how to test Rails applications which struck me as odd at the time.
That&amp;#8217;s probably the reason I read it several times.&lt;/p&gt;

&lt;p&gt;A few weeks ago I watched Gregory Moeck&amp;#8217;s &lt;a href="http://confreaks.net/videos/659-rubyconf2011-why-you-don-t-get-mock-objects"&gt;Why You Don&amp;#8217;t Get Mock Objects&lt;/a&gt; and I was stung by the same bug only more deeply,
this time.&lt;/p&gt;

&lt;p&gt;Using that video as a starting point I then roamed Gregory&amp;#8217;s blog for
more and felt like I was beginning to grasp it. Now, obviously, I&amp;#8217;m at the
beginning of this journey and still have a lot of teeth-cutting to do.
Nevertheless, I want to share with you the gems I&amp;#8217;ve found so far.&lt;/p&gt;

&lt;p&gt;Gregory&amp;#8217;s blog has a very good primer on the difference between stubs
and mocks: &lt;a href="http://gmoeck.github.com/2011/10/26/stubbing-is-not-enough"&gt;&amp;#8220;Stubbing is Not Enough&amp;#8221;&lt;/a&gt;. I&amp;#8217;d even go
as far as to claim that it explains its subject better than Martin
Fowler&amp;#8217;s classic &lt;a href="http://martinfowler.com/articles/mocksArentStubs.html"&gt;&amp;#8220;Stubs Are Not Mocks&amp;#8221;&lt;/a&gt;, although that
latter goes into more detail and is a definite must-read, too.&lt;/p&gt;

&lt;p&gt;James Golick has another great piece that drives home the point better
than his first post I mentioned: &lt;a href="http://jamesgolick.com/2010/3/10/on-mocks-and-mockist-testing.html"&gt;&amp;#8220;On Mocks and Mockist Testing&amp;#8221;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Along comes Avdi Grimm with his strict sounding &lt;a href="http://avdi.org/devblog/2011/07/05/demeter-its-not-just-a-good-idea-its-the-law/"&gt;&amp;#8220;Demeter: It’s not just a good idea. It’s the law.&amp;#8221;&lt;/a&gt;
, with a very interesting discussion in the comments. The same gentleman
wrote &lt;a href="http://avdi.org/devblog/2011/09/06/making-a-mockery-of-tdd/"&gt;&amp;#8220;Making a Mockery of TDD&amp;#8221;&lt;/a&gt; in which he
touches on the concept of using mocks as a design tool.&lt;/p&gt;

&lt;p&gt;Nick Kallen&amp;#8217;s &lt;a href="http://magicscalingsprinkles.wordpress.com/2010/02/08/why-i-love-everything-you-hate-about-java/"&gt;&amp;#8220;Why I love everything you hate about Java&amp;#8221;&lt;/a&gt; is clearly provocative
and definitely worth to contemplate on. It is also the only one of the bunch that
does not use Ruby (but Scala) for the code examples.&lt;/p&gt;

&lt;p&gt;Finally it seems like the fountainhead in the matter is the &lt;a href="growing"&gt;&amp;#8220;Growing Object-Oriented Software, Guided by Tests&amp;#8221;&lt;/a&gt;
book by Steve Freeman and Nat Pryce. I&amp;#8217;ve only gotten until putting it
on my reading list so please chime in if you did read it.&lt;/p&gt;

&lt;p&gt;Please, also pipe in if there are any materials in the subject you&amp;#8217;d
recommend. It would also be cool to see open source projects that extensively use mocks for testing, the only
one I found so far is &lt;a href="https://github.com/jamesgolick/friendly"&gt;friendly&lt;/a&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=V7nPh5Y07-o:hTlljCzdswU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=V7nPh5Y07-o:hTlljCzdswU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=V7nPh5Y07-o:hTlljCzdswU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=V7nPh5Y07-o:hTlljCzdswU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/V7nPh5Y07-o" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2011/11/30/an-annotated-assortment-on-mockist-testing.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Event loop primer]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/o4l_dRBew-w/event_loop_primer.html" />
    <updated>2011-10-19T00:06:00+02:00</updated>
    <id>http://balinterdi.com/2011/10/19/event_loop_primer</id>
    <content type="html">&lt;p&gt;I recently got into developing a web application with node.js (aka &lt;a href="http://teddziuba.com/2011/10/node-js-is-cancer.html"&gt;cancer&lt;/a&gt;).
Coming from a synchronous world, it took (and to be honest, still takes)
quite a while to grok how writing asynchronous code differs from my
previous experiences (AJAX calls with jQuery only go that far).&lt;/p&gt;

&lt;p&gt;As with many fine technologies or methods (TDD, NoSQL, functional
programming come to mind) it&amp;#8217;s your whole
thinking that has to change. In this post I want to share an example
from &lt;a href="http://pragprog.com/book/tbcoffee/coffeescript"&gt;Trevor Burnham&amp;#8217;s excellent Coffeescript book&lt;/a&gt; that gave me one
of those aha moments.&lt;/p&gt;

&lt;div&gt;&lt;script src='https://gist.github.com/1297011.js'&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;countdown = 10
h = setInterval -&amp;gt;
 countdown--
, 100
do (-&amp;gt;) until countdown is 0
clearInterval h
console.log 'Surprise!'&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;


&lt;p&gt;(If you don&amp;#8217;t read Coffeescript code, you can go to the &lt;a href="http://jashkenas.github.com/coffee-script/"&gt;Coffeescript web site&lt;/a&gt;
and paste the above example in to get compiled Javascript)&lt;/p&gt;

&lt;p&gt;The example above is broken. It gets stuck at the &lt;code&gt;until countdown is 0&lt;/code&gt;
row. In an event loop system events (callbacks) only get run after the &amp;#8220;main line&amp;#8221;
of execution (or, in other words, all other code) has completed.
So the until loop blocks out the callback of the setInterval,
countdown never gets decremented and thus an endless loop ensues.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m sure that there are many ways to fix this, I came up with the
following (and wonder if there is one closer to the original):&lt;/p&gt;

&lt;div&gt;&lt;script src='https://gist.github.com/1297018.js'&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;countdown = 10
h = setInterval -&amp;gt;
  countdown--
  if countdown is 0
    console.log 'Surprise'
    clearInterval h
, 100&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;


&lt;p&gt;And that&amp;#8217;s it. I hope this simple example pushes you up on that pesky learning curve.&lt;/p&gt;

&lt;p&gt;(The snippet was published by the kind permission of the author.)&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=o4l_dRBew-w:lvLAGHigFx4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=o4l_dRBew-w:lvLAGHigFx4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=o4l_dRBew-w:lvLAGHigFx4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=o4l_dRBew-w:lvLAGHigFx4:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/o4l_dRBew-w" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2011/10/19/event_loop_primer.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Five wasted years - on the futility of university education]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/70upSnjXboo/five-wasted-years-futility-of-university-education.html" />
    <updated>2011-09-28T00:00:00+02:00</updated>
    <id>http://balinterdi.com/2011/09/28/five-wasted-years-futility-of-university-education</id>
    <content type="html">&lt;p&gt;I graduated from the Technical University of Budapest to earn a M.Sc. in
Software Engineering. Albeit it is supposed to be an asset on my CV I&amp;#8217;ll
argue below that the long years of university education was just not worth it.&lt;/p&gt;

&lt;p&gt;When trying to summarize what advantage university education
brought me there is precious little I can think of. Five years is a lot of
time to spend without actually getting something out of it for one&amp;#8217;s
professional career.&lt;/p&gt;

&lt;p&gt;Obviously I&amp;#8217;ve formed my opinion based on my university experience which
might not (and probably &lt;em&gt;is&lt;/em&gt; not) be applicable to all higher education.
Philosophy, economics and law all require different formation
and practice might be harder (or outright dangerous) to attain in some
areas (think medicine).&lt;/p&gt;

&lt;p&gt;Also, there is a great variance between countries although even the famously high-standard
US education system seems to yield not actual but rather
looks-good-on-my-CV benefits, say some &lt;a href="http://techcrunch.com/2011/04/10/peter-thiel-were-in-a-bubble-and-its-not-the-internet-its-higher-education/" title="Peter Thiel: Education Bubble"&gt;smart&lt;/a&gt; &lt;a href="http://www.economist.com/node/18750658" title="Stephen Wolfram"&gt;guys&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Learn to learn?&lt;/h2&gt;

&lt;p&gt;Tech is changing extremely rapidly. Today&amp;#8217;s hotness could be a thing of
the past in a few years. Consequently universities should not try to keep up with the
pace and teach students state-of-the-art stuff. Higher education needs to transcend
short-term utility and provide a base one can build on for the rest of
his career. So we were told or made to believe.&lt;/p&gt;

&lt;p&gt;What is probably considered the essence of higher education is &amp;#8220;learn to
learn&amp;#8221;. It is the idea that universities need to teach future-engineers
how to quickly adapt to new fields and techniques (programming
languages, databases, architectures, etc.).&lt;/p&gt;

&lt;p&gt;This is appealing but universities don&amp;#8217;t do that. I had to sit through
long hours of material not even vaguely related to software engineering.
The practical stuff (e.g programming languages) was taught with stone age style methods
(programming on paper).  The other subjects, those that were supposed to provide us the broad
vision, I suppose, were way too much in volume and failed to achieve that goal.&lt;/p&gt;

&lt;h2&gt;Make to learn&lt;/h2&gt;

&lt;p&gt;In my current job I&amp;#8217;m lucky to work with some guys who dropped out of
college and started to work. They might not
know about &lt;a href="http://en.wikipedia.org/wiki/Prim's_algorithm" title="Prim's algorithm"&gt;Prim&amp;#8217;s algorithm&lt;/a&gt; or the &lt;a href="http://en.wikipedia.org/wiki/Intermediate_value_theorem" title="Intermediate value theorem"&gt;intermediate value theorem&lt;/a&gt;,
but I think the result of the time they spent making things greatly surpass the time I
spent learning the above.&lt;/p&gt;

&lt;p&gt;Programming (or, in its more CV-friendly, hire-me name: software
engineering) is a task that could be the modern equivalent of wood carving.
You can learn all that you want about the craft, the only thing that
really matters is doing it, a lot. Only, programming is way better.
There is virtually no waste (unless you publish what you make :) ) and
the tools are more accessible and cheaper.&lt;/p&gt;

&lt;p&gt;Take it from someone who, unlike most kiddos at the university, started
programming late: it feels awkward and weird at first. And then the
second and third time, too. Slowly, though, you start to feel like it&amp;#8217;s actually
fun and sometimes more than that. You&amp;#8217;re building something which you&amp;#8217;ll
look at ashamedly a few months later but at least your program does something extraordinary,
like sorting a list of numbers. That&amp;#8217;s science!&lt;/p&gt;

&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/B-tree" title="B-tree"&gt;Math data constructs&lt;/a&gt;, probability theory and cryptography notwithstanding,
have you got this feeling of coolness (dare I say, awe) out of university lectures?&lt;/p&gt;

&lt;h2&gt;Total waste, really?&lt;/h2&gt;

&lt;p&gt;In fairness, and as a measure to counter my arrogance, I had to consider arguments
on the pro-education side, too. Here is what I came up with:&lt;/p&gt;

&lt;h3&gt;Math&lt;/h3&gt;

&lt;p&gt;When faced with a programming challenge I
can recall on some occasions an algorithm used to resolve a similar problem.
That&amp;#8217;s not to say you can&amp;#8217;t google up a solution if you have a vague
idea what to look for. Nevertheless if you can mentally page through the solutions
for a given problem from your university classes, their time and space
needs and their constraints then you surely save a lot of time.
I forgot all the relevant facts about any algorithm and have to look it
up every single time, but it could be me.&lt;/p&gt;

&lt;h3&gt;Deciding on one&amp;#8217;s vocation&lt;/h3&gt;

&lt;p&gt;Most kids don&amp;#8217;t know what to do with their life when they are 18. Real
life still seems distant and most want a few more years of canteen,
beers and idling. Whether it is beneficial for them or society
(taxpayers) as a whole to be allowed to do that is another matter.
Nevertheless, I&amp;#8217;m convinced that a high number of students can have a
clearer picture about whether they want to do &amp;#8220;computer science&amp;#8221; for the
rest of their lives after a couple of years.&lt;/p&gt;

&lt;h3&gt;Outstanding teachers&lt;/h3&gt;

&lt;p&gt;Even though I reckon you can learn everything you need to know on your
own (from the Internet), having a good teacher can squeeze your
learning curve. Although I believe this is more attainable with a small
group (and even more in a one-to-one, mentoring relationship) it&amp;#8217;s
definitely possible for an outstanding teacher to speed up absorbing
knowledge with a bigger group, too. Unfortunately, with one notable
exception, my teachers were not of this type, but
that&amp;#8217;s a weak argument against college education in general.&lt;/p&gt;

&lt;p&gt;Even if all these pro-education arguments are valid, however, a couple
of years is surely enough to derive all the advantages they bring.
Then, you still have 3 years to go and carve wood.&lt;/p&gt;

&lt;h2&gt;On navigation&lt;/h2&gt;

&lt;p&gt;Let me finally share a quote I&amp;#8217;ve just found in Walden by H.D. Thoreau and that
summarizes my intent with this post in one swell sentence:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;To my astonishment I was informed on leaving college that I had studied&lt;br/&gt;navigation! &amp;#8211; why, if I had taken one turn down the harbor I should&lt;br/&gt;have known more about it.&lt;/p&gt;&lt;footer&gt;&lt;strong&gt;Henry David Thoreau&lt;/strong&gt; &lt;cite&gt;Walden&lt;/cite&gt;&lt;/footer&gt;&lt;/blockquote&gt;


&lt;h2&gt;Please defend the status quo (or indulge in bashing it)&lt;/h2&gt;

&lt;p&gt;As I stated in the introduction, my opinion is just a drop in the ocean,
a tiny slice in a big cake, a lone voice in the NY Stock Exchange (you
get my point).&lt;/p&gt;

&lt;p&gt;If you &lt;a href="http://www.codigoergosum.com/2011/09/28/five-wasted-years-futility-of-university-education.html" title="Comments"&gt;share your opinion&lt;/a&gt;, there will be two voices already and we&amp;#8217;ll
have more information to decide about whether we should advise our children to go
to college, for example. Then three. We may even reach four voices.&lt;/p&gt;

&lt;p&gt;Joking aside, if you went to college to learn computer science in Hungary
or in another country, I&amp;#8217;m interested to &lt;a href="http://www.codigoergosum.com/2011/09/28/five-wasted-years-futility-of-university-education.html" title="Comments"&gt;hear your opinion&lt;/a&gt;. If you
studied something else, don&amp;#8217;t be discouraged, please &lt;a href="http://www.codigoergosum.com/2011/09/28/five-wasted-years-futility-of-university-education.html" title="Comments"&gt;share also&lt;/a&gt;. My
points are mostly valid for computer science but I&amp;#8217;m curious to hear
which other fields they hold true in (or in which fields they don&amp;#8217;t).&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=70upSnjXboo:zr8IrD5hVpI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=70upSnjXboo:zr8IrD5hVpI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=70upSnjXboo:zr8IrD5hVpI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=70upSnjXboo:zr8IrD5hVpI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/70upSnjXboo" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2011/09/28/five-wasted-years-futility-of-university-education.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Powered by Octopress]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/hfRQi04l1zw/powered-by-octopress.html" />
    <updated>2011-09-05T21:22:00+02:00</updated>
    <id>http://balinterdi.com/2011/09/05/powered-by-octopress</id>
    <content type="html">&lt;p&gt;&lt;a href="http://octopress.org/"&gt;Octopress&lt;/a&gt; is a blogging engine on top of Jekyll. It got my attention
since it provides themes and a layout that looks great on mobile
devices, too.&lt;/p&gt;

&lt;p&gt;I had been playing with the idea to do my own simplistic theming long enough
to realize that I would never do it. The other feature I like is its plugin system:
some I&amp;#8217;ll use right away (e.g Github style codeblock) but I also like
the idea that I can write a plugin for any specific need that might
arise later.&lt;/p&gt;

&lt;p&gt;I had had my blog on Jekyll so migration was not really hard. I hit a
few minor roadblocks on the way but &lt;a href="http://octopress.org/docs/"&gt;documentation&lt;/a&gt; is great and the author,
Brandon Mathis was really helpful on the &lt;a href="https://convore.com/octopress/"&gt;support forum&lt;/a&gt; so
I could eventually sort them out.&lt;/p&gt;

&lt;p&gt;If you like to &lt;a href="http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html"&gt;blog like a hacker&lt;/a&gt;, want to own your
content and don&amp;#8217;t want to be bothered with styling, I encourage you to
join &lt;a href="https://github.com/imathis/octopress/wiki/Octopress-Sites"&gt;the squid team&lt;/a&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=hfRQi04l1zw:knP3ThgKN0k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=hfRQi04l1zw:knP3ThgKN0k:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=hfRQi04l1zw:knP3ThgKN0k:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=hfRQi04l1zw:knP3ThgKN0k:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/hfRQi04l1zw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2011/09/05/powered-by-octopress.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Git rebase to fix your local commits]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/vSTx21owDC8/git-rebase-to-fix-your-local-commits.html" />
    <updated>2011-07-19T00:00:00+02:00</updated>
    <id>http://balinterdi.com/2011/07/19/git-rebase-to-fix-your-local-commits</id>
    <content type="html">&lt;p&gt;Let&amp;#8217;s say you have the following three commits in your local repository:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;% git log -3 --oneline
&lt;/span&gt;&lt;span class='line'&gt;b648f1a Fix propagating errors in findOrInitialize. (28 seconds ago)
&lt;/span&gt;&lt;span class='line'&gt;8789cd1 Non-destructive filtering for bumblebees. (12 hours ago)
&lt;/span&gt;&lt;span class='line'&gt;1a35285 Propagate errors the node.js way. (14 hours ago)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The last commit, b648f1a conceptually belongs to the first one, 1a35285.
It only came later because say you haven&amp;#8217;t run the tests before
committing it and only realized later you introduced a bug. Or some
other misdemeanor. Whatever the background is, it would be great if
there was a way to squash the two related commits together. Turns out
there is: interactive rebase.&lt;/p&gt;

&lt;p&gt;The syntax of the git-rebase is the following:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;git rebase [-i | --interactive] [options] [--onto &amp;lt;newbase&gt;]
&lt;/span&gt;&lt;span class='line'&gt;             &amp;lt;upstream&gt; [&amp;lt;branch&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;What happens when you do git rebase is that the commits that are on the current
branch but are not in upstream are saved. The current branch is reset to
upstream and then the saved commits are replayed on top of this.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s worth to mention that you should only do this if you have not
pushed out these changesets to a remote where others might have pulled
from it. Rebase creates new commits and if your collaborators pull the
new commits, chaos can ensue. (See &amp;#8220;Perils of Rebase&amp;#8221; in the &lt;a href="http://progit.org/book/ch3-6.html"&gt;ProGit
book&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This can be used to achieve what we want:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;% git rebase -i HEAD~3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Since the commits that are on the current branch but not on the commit
three commits from here are the last three commits, here is what we get:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;pick 1a35285 Propagate errors the node.js way.
&lt;/span&gt;&lt;span class='line'&gt;pick 8789cd1 Non-destructive filtering for bumblebees.
&lt;/span&gt;&lt;span class='line'&gt;pick b648f1a Fix propagating errors in findOrInitialize.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;We want to meld the &amp;#8220;fix&amp;#8221; commit into the &amp;#8220;propagate&amp;#8221; commit since
that&amp;#8217;s how it should have been in the first place. So we move b648f1a up and
squash it into the previous commit:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;pick 1a35285 Propagate errors the node.js way.
&lt;/span&gt;&lt;span class='line'&gt;squash b648f1a Fix propagating errors in findOrInitialize.
&lt;/span&gt;&lt;span class='line'&gt;pick 8789cd1 Non-destructive filtering for scales.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;After a successful rebase this is how the new log looks like:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;% git log -3 --oneline
&lt;/span&gt;&lt;span class='line'&gt;73eed18 Non-destructive filtering for bumblebees. (9 seconds ago)
&lt;/span&gt;&lt;span class='line'&gt;1e63d17 Propagate errors the node.js way. (39 seconds ago)
&lt;/span&gt;&lt;span class='line'&gt;1b24891 Minor fixes in Bumblebee buzzing. (16 hours ago)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Note that the three commits we had before have now been nicely compacted
into two, and the propagation commit is now consistent and fixed. It can
now be pushed.&lt;/p&gt;

&lt;p&gt;ps. You might wonder what we use bumblebees for in our project. Actually
they are faux. They serve to obfuscate real names in propietary code.
I hope I can one day write code where bumblebees will be first-class
citizens, though.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=vSTx21owDC8:GqPvzZq-DA0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=vSTx21owDC8:GqPvzZq-DA0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=vSTx21owDC8:GqPvzZq-DA0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=vSTx21owDC8:GqPvzZq-DA0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/vSTx21owDC8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2011/07/19/git-rebase-to-fix-your-local-commits.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Don't Tell Michelle, Facebook privacy as it should be]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/3BTvRuLD1Ik/dont-tell-michelle-facebook-privacy-as-it-should-be.html" />
    <updated>2010-10-10T00:00:00+02:00</updated>
    <id>http://balinterdi.com/2010/10/10/dont-tell-michelle-facebook-privacy-as-it-should-be</id>
    <content type="html">&lt;p&gt;It&amp;#8217;s been a quiet four months over here. My excuse is that I&amp;#8217;ve been working. I joined a startup, &lt;a href="http://secretsaucepartners.com"&gt;Secret Sauce Partners&lt;/a&gt; in June and we have started to build our first product a couple of weeks later. Now I am proud (actually, quite proud) to announce that we have released a first version last week.&lt;/p&gt;

&lt;h2&gt;The problem we are solving&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m sure you have a Facebook account. You probably have around &lt;a href="http://www.facebook.com/press/info.php?statistics"&gt;130 &amp;#8220;friends&amp;#8221;&lt;/a&gt;. Chances are you want to share lots of things but on several occasions you don&amp;#8217;t want to tell everybody. Sure, you can create friend lists and post to them based on what you want to say. Or, you can pick individual friends for your message (good luck with that if you would like to speak to more than 3 friends). It would definitely make sense (and would hugely improve the state of the world!) if you only showed your Farmville achievements to your friends who play Farmville and nobody else. Especially not your colleagues during work hours.&lt;/p&gt;

&lt;p&gt;Wouldn&amp;#8217;t it be cool if you did not have to fiddle with setting the proper audience of your posts every single time you share something? If the people whom you post to would be determined from the content and the context of your message? Better still, if friends that join later could not see your posts prior to that?&lt;/p&gt;

&lt;h2&gt;The solution&lt;/h2&gt;

&lt;p&gt;Let&amp;#8217;s go back to Farmville-land (I know, I know, but bear with me for a few more minutes). If you only want to show your Farmville posts to selected people the only way to achieve it is to set your default privacy to that list of selected friends prior to diving in to FarmVille. Then you set it back to your default posting setting. Not quite comfortable.&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s where our application comes into the picture. To solve the above problem, you set up a rule that says:
&amp;#8220;Hide posts from Farmville posted during Work Hours from my Co-Workers&amp;#8221;. You lay back, go feed your piggies, and water your sunflowers safe in the knowledge that your colleagues will not know about it. Suppose you don&amp;#8217;t want your mom to know where you spend your weekends. Here is your rule: &amp;#8220;Hide All posts from Foursquare from Family&amp;#8221;. Feeling the urge to swear like a sailor some times and don&amp;#8217;t want your little cousins or nieces to know about it? &amp;#8220;Always hide posts with Swear Words from Kids&amp;#8221;. Don&amp;#8217;t want to spam your Twitter followers on Facebook? &amp;#8220;Always hide posts from Twitter from Twitter followers&amp;#8221;. Then, there are the &amp;#8220;Show&amp;#8221; rules*. For example, an even more sensible rule for Farmville posts could be: &amp;#8220;Always show posts from Farmville to Players&amp;#8221;.
(* &amp;#8220;Show rules&amp;#8221; are the next feature we are going to work on.)&lt;/p&gt;

&lt;p&gt;You see, the possibilities are endless, so why don&amp;#8217;t you &lt;a href="http://donttellmichelle.com/"&gt;set up your own rules and give it a try&lt;/a&gt;? I bet you will never want to go back to (broken) standard Facebook privacy setting.&lt;/p&gt;

&lt;p&gt;Ah, and if you don&amp;#8217;t want your wife to know how much high-cholesterol food you eat, then &lt;a href="http://blogs.suntimes.com/sweet/2010/03/dont_tell_michelle_obama_says.html"&gt;&amp;#8220;Don&amp;#8217;t Tell Michelle&amp;#8221;&lt;/a&gt;&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=3BTvRuLD1Ik:xd9mTaoEMqo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=3BTvRuLD1Ik:xd9mTaoEMqo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=3BTvRuLD1Ik:xd9mTaoEMqo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=3BTvRuLD1Ik:xd9mTaoEMqo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/3BTvRuLD1Ik" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2010/10/10/dont-tell-michelle-facebook-privacy-as-it-should-be.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[It's a spec, not a test]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/RRq4t4l-pac/its-a-spec-not-a-test.html" />
    <updated>2010-06-03T00:00:00+02:00</updated>
    <id>http://balinterdi.com/2010/06/03/its-a-spec-not-a-test</id>
    <content type="html">&lt;p&gt;You must have heard the question several times on the Rails mailing list and different IRC channels: &amp;#8220;Should I test validates_uniqueness_of&amp;#8221;? The standard answer to that one is &amp;#8220;No, you definitely should not. It&amp;#8217;s Rails framework code, and it&amp;#8217;s already thoroughly tested. If you followed this path, you should also test whether objects are properly persisted in the database.&amp;#8221;&lt;/p&gt;

&lt;p&gt;I think, however, that the question is wrong and thus you can not give a correct answer. It is wrong because validates_uniqueness_of is the implementation, not the requirement. If you approach it from this angle, the question turns into whether you should test the specific implementation or whether you should verify that (business) requirements are met.&lt;/p&gt;

&lt;p&gt;That, in turn, comes down to tests vs. specs (short for specifications) and this is again an opportunity for specs to shine. If you write specs instead of tests (or, to put it in a more mind-warping way: if your tests are actually specs), then the above question is a no-brainer: it&amp;#8217;s part of the specification that no two users can have the same email address, so you must have a spec for it:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;user_spec.rb &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='rb'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;has a unique email address&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="no"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;jeff@topnotch.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;jeff@topnotch.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;     &lt;span class="n"&gt;raise_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;ActiveRecord&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="ss"&gt;:RecordInvalid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;On the other hand, if you stick with calling your tests tests (how orthodox! ;) ) then not only you have to think (which consumes a lot of resources), but you can also come to the wrong conclusion and emit a strong business requirement from your test suite. And then you might not remember to have the implementation for it after modifying the code for whatever reason. And then bad things might happen.&lt;/p&gt;

&lt;p&gt;(This thought came to me when coming to work in the subway this morning. I was never quite comfortable with the name &amp;#8220;specs&amp;#8221; but now it&amp;#8217;s starting to make a lot of sense to me. You are encouraged to disagree. Dissent is what makes the world progress.)&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=RRq4t4l-pac:Epw3Vixh22Q:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=RRq4t4l-pac:Epw3Vixh22Q:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=RRq4t4l-pac:Epw3Vixh22Q:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=RRq4t4l-pac:Epw3Vixh22Q:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/RRq4t4l-pac" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2010/06/03/its-a-spec-not-a-test.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Remove'em trailing whitespaces!]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/Ev-jvDH2_TM/remove-trailing-whitespaces.html" />
    <updated>2010-02-16T00:00:00+01:00</updated>
    <id>http://balinterdi.com/2010/02/16/remove-trailing-whitespaces</id>
    <content type="html">&lt;p&gt;Some of you reading this probably use TextMate. It is an excellent editor with two caveats. The first is that you can only see one file in the editing window (no screen split), the other is that there is no save hook. This latter gave me headaches since I can&amp;#8217;t stand any trailing whitespace in source code and the easiest solution would have been to run a script to remove those when the file is saved.&lt;/p&gt;

&lt;p&gt;Without further ado I&amp;#8217;ll paste my solution below. Obviously this is not a difficult task to accomplish so the goal is to share not to show off. I use Git for SCM and the following solution parses out the files that have been modified and runs the whitespace eraser script for those. If you use something else (why do you?) you should obviously change the first building block:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;parse_modified_files_from_git_status.rb &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='rb'&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby -wn&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;modified_file_pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^#\s+(?:modified|new file):\s+(.*)$/&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;modified_file_pattern&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;rm_trailing_whitespace.rb &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='rb'&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby -wn&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="vg"&gt;$:&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;trailing_whitespace_eraser&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;TrailingWhiteSpaceEraser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rm_trailing_whitespace!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;




&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;trailing_whitespace_eraser.rb &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='rb'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TrailingWhiteSpaceEraser&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="no"&gt;FILE_TYPES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;feature&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;yml&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;erb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;haml&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rm_trailing_whitespace_from_file!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;trimmed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readlines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[\t ]+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;w&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trimmed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rm_trailing_whitespace!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;directory?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/**/*.{&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;FILE_TYPES&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&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="n"&gt;rm_trailing_whitespace_from_file!&lt;/span&gt;&lt;span class="p"&gt;(&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;chomp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And then you run it by typing:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;rtwsp.sh &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='line'&gt;git status | parse_modified_files_from_git_status.rb | rm_trailing_whitespace.rb
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;If you decide to use this, it is more convenient to &lt;a href="http://gist.github.com/raw/305654/568290aa63ee3b0b3748b5041654f94ce45f4e5b/erase_trailing_whitespace.rb"&gt;download the raw source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hopefully I did my tiny bit to have less trailing whitespace in OS code.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=Ev-jvDH2_TM:6bCXyIKECGQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=Ev-jvDH2_TM:6bCXyIKECGQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=Ev-jvDH2_TM:6bCXyIKECGQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=Ev-jvDH2_TM:6bCXyIKECGQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/Ev-jvDH2_TM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2010/02/16/remove-trailing-whitespaces.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[2010 is the year of the Javascript]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/ATSzNO51Dj0/2010-is-the-year-of-the-javascript.html" />
    <updated>2010-01-28T00:00:00+01:00</updated>
    <id>http://balinterdi.com/2010/01/28/2010-is-the-year-of-the-javascript</id>
    <content type="html">&lt;p&gt;If you&amp;#8217;ve read the &lt;a href="http://pragprog.com/titles/tpp/the-pragmatic-programmer"&gt;The Pragmatic Progammer - From Journeyman to Master&lt;/a&gt; (and if you have not, believe me, you should) you might remember one precious advice: learn a new programming language every year. So when the year draws close to its end (around April, that is) I really start thinking about which language should be the one for me next year.&lt;/p&gt;

&lt;p&gt;This reflection is very pleasant; it is such a joy to immerse oneself into a new language, to slowly discover its structure, its subtleties and learn new ways of thinking, of approaching a problem (because that&amp;#8217;s probably the biggest gain of it, even surpassing adding another language to your arsenal) that its prospect is already rewarding in itself.&lt;/p&gt;

&lt;p&gt;My choice in 2009 fell on &lt;a href="http://clojure.org"&gt;Clojure&lt;/a&gt;. I love functional programming, its elegance, its cleanness, its statelessness and after getting my feet wet with &lt;a href="http://www.paulgraham.com/acl.html"&gt;ANSI Common LISP&lt;/a&gt; a while ago I felt like Clojure would propel me on my way of becoming an FP guru. Guided by &lt;a href="http://pragprog.com/titles/shcloj"&gt;a great book&lt;/a&gt; I wrote a couple of, admittedly &lt;a href="http://github.com/balinterdi/clojure_exercises/blob/master/lzw/compressor.clj"&gt;not too difficult&lt;/a&gt; &lt;a href="http://github.com/balinterdi/clojure_exercises/tree/master/sudoku/game.clj"&gt;exercises&lt;/a&gt;  (hey, a &lt;a href="http://github.com/balinterdi/clojure_exercises/tree/master/sudoku/game.clj"&gt;sudoku solver&lt;/a&gt; is already something, isn&amp;#8217;t it?) and I would certainly like to continue to do more with it in 2010.&lt;/p&gt;

&lt;p&gt;Now, on to 2010.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://mir.aculo.us"&gt;Thomas Fuchs&lt;/a&gt; is certainly right when he predicts that &lt;a href="http://mir.aculo.us/2010/01/07/web-developments-next-decade/"&gt;Javascript will play an increasingly significant role in web development&lt;/a&gt;. I was definitely wrong when I had thought of JS as an undebuggable, structure- and featureless, incoherent language. Of course, you can write Javascript code that is like this but I now think that -at least in the case of Javascript- this tells more about the craftsman than about the language.&lt;/p&gt;

&lt;p&gt;Make no mistakes, I can already do Javascript! I can miraculously make a check box appear if you click on a link, or update a database record without reloading the page when you press a button and a ton more such wizardry, really. However, I always felt like there was a whole lot more to Javascript than putting some dumb-looking functions in a file and then include it from my html (no, I don&amp;#8217;t think inlining it makes a difference) and I felt uneasy about my javascript functions just standing there on their own without any apparent belonging to a group or some kind of cohesive force or idea that holds them together.&lt;/p&gt;

&lt;p&gt;My recent enthusiasm comes from the fact that I had to browse through some of the source code of &lt;a href="http://script.aculo.us/"&gt;scriptaculous&lt;/a&gt; and I really liked what I saw. The enthusiasm &lt;a href="http://www.codigoergosum.com/2008/10/09/javascript-method-chain.html"&gt;is not totally new&lt;/a&gt; but looking at that source code demolished the last shreds of my Javascript skepticism, so to speak. So a year later than &lt;a href="http://www.rubyrailways.com/learn-at-least-one-new-language-every-year/"&gt;Peter Szinek&lt;/a&gt; I am hopping on the same train: Javascript, here I come! If you have read a good book that enhanced your Javascript foo, please tell me about it in the comments.&lt;/p&gt;

&lt;p&gt;And you? Have you already chosen your language for 2010?&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=ATSzNO51Dj0:aXx-jUg99ew:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=ATSzNO51Dj0:aXx-jUg99ew:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=ATSzNO51Dj0:aXx-jUg99ew:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=ATSzNO51Dj0:aXx-jUg99ew:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/ATSzNO51Dj0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2010/01/28/2010-is-the-year-of-the-javascript.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Twuckoo 0.3.5 - With email notification]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/G2gLlg0Soq8/twuckoo-0.3.5-with-email-notification.html" />
    <updated>2010-01-26T00:00:00+01:00</updated>
    <id>http://balinterdi.com/2010/01/26/twuckoo-0.3.5-with-email-notification</id>
    <content type="html">&lt;p&gt;As some of you might know, I am running a &lt;a href="http://twitter.com/pragthinklearn"&gt;few&lt;/a&gt; &lt;a href="http://twitter.com/daily_oblique"&gt;twitter&lt;/a&gt; &lt;a href="http://twitter.com/wikipedia_tfa"&gt;channels&lt;/a&gt; that use my brainchild, &lt;a href="http://github.com/balinterdi/twuckoo"&gt;twuckoo&lt;/a&gt;, to periodically send a tweet.&lt;/p&gt;

&lt;p&gt;In &lt;a href="http://twitter.com/pragthinklearn"&gt;two&lt;/a&gt; &lt;a href="http://twitter.com/daily_oblique"&gt;of&lt;/a&gt; these cases the program takes its next message from a file and takes care not to tweet the same thing twice by keeping track of the messages already sent. This means, however, that the pool of sendable messages are depleted after a while and the script simply does not send any more tweets, the channel becomes dead.&lt;/p&gt;

&lt;p&gt;This has happened a couple of times in the past and I only realized it with a few days of delay which is kind of awkward (if you were subscribed to one of these accounts, I apologize). So I decided to have twuckoo send a notification in this case so I can go in and refill its queue. Hence twuckoo version 0.3.5 was born which sends an email to the address set in the configuration file when it failed to send a message.&lt;/p&gt;

&lt;p&gt;To install it, add &lt;a href="http://gemcutter.org"&gt;gemcutter&lt;/a&gt; to the list of gem sources if you haven&amp;#8217;t already:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;install.sh &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='line'&gt;gem &lt;span class="nb"&gt;source&lt;/span&gt; --add http://gemcutter.org
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And install twuckoo:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;install.sh &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='line'&gt;gem install twuckoo
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You might be thinking that it would be more straightforward to have the program replenish itself so that no intervention from the part of the developer is needed. And you would be right, this could be a task for the next version. I still think it is a good idea to send a notification so the (wo)man in charge knows it happened.&lt;/p&gt;

&lt;p&gt;So go ahead, have a look at &lt;a href="http://github.com/balinterdi/twuckoo"&gt;the README&lt;/a&gt;, set up your own twitter channel and don&amp;#8217;t fret about when the queue would run dry. You&amp;#8217;ll be notified.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=G2gLlg0Soq8:wyZq4dFV62g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=G2gLlg0Soq8:wyZq4dFV62g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=G2gLlg0Soq8:wyZq4dFV62g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=G2gLlg0Soq8:wyZq4dFV62g:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/G2gLlg0Soq8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2010/01/26/twuckoo-0.3.5-with-email-notification.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[My tech book list for 2009]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/ECnbWzciVME/my-tech-book-list-for-2009.html" />
    <updated>2010-01-11T00:00:00+01:00</updated>
    <id>http://balinterdi.com/2010/01/11/my-tech-book-list-for-2009</id>
    <content type="html">&lt;p&gt;The title probably tells it all, below is the list of technical books I read in 2009. I am -unfortunately :)- not getting paid for any recommendation that lies herein.&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://www.pragprog.com/titles/mjwti/"&gt;My Job Went to India&lt;/a&gt; &lt;span class="author"&gt;&lt;em&gt;by Chad Fowler&lt;/em&gt;&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;This one is a real motivation booster. Or it might function like love in the case of separated lovers: if you were motivated in the first place, you&amp;#8217;ll get a kick out of this book and want to do everything it recommends right from the next day. If you were not it might depress you to have to do so many things to stay afloat. Full of useful advices mostly drawn from the author&amp;#8217;s personal experience in India. 5/5!&lt;/p&gt;

&lt;p&gt;(There is a second, reworked version under the name: &lt;a href="http://pragprog.com/titles/cfcar2/the-passionate-programmer"&gt;The Passionate Programmer&lt;/a&gt;, you should probably buy that one.)&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://www.joelonsoftware.com/uibook/fog0000000249.html"&gt;User Interface Design for Programmers&lt;/a&gt; &lt;span class="author"&gt;&lt;em&gt;by Joel Spolsky&lt;/em&gt;&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;I real like Joel Spolsky&amp;#8217;s essays both for the content and for his witty style. I laughed out loud on several remarks in this book, too. The book reaffirms how important good UI is, makes it accessible for programmers by giving guidelines and provides some examples of good (and especially bad) examples. Its style makes the &amp;#8220;dry&amp;#8221; technical stuff fun to read.&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://www.pomodorotechnique.com/resources.html"&gt;The Pomodoro Technique&lt;/a&gt; &lt;span class="author"&gt;&lt;em&gt;by Francesco Cirillo&lt;/em&gt;&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;A time-management and productivity tool, the Pomodoro Technique is the latest craze. The technique can be summarized in a few paragraphs, the details fill about 40 pages which comprise this book. &lt;a href="http://www.pomodorotechnique.com/resources/cirillo/ThePomodoroTechnique_v1-3.pdf"&gt;The e-book&lt;/a&gt; can be downloaded for free. Although I do not follow all the advices described in the book fully (like administering the tasks you have done at the end of each day) I think the technique is a great way to achieve focus especially if you have problems with it. (The PragProgs have also recently published &lt;a href="http://pragprog.com/titles/snfocus/pomodoro-technique-illustrated"&gt;a book about it&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://pragprog.com/titles/shcloj"&gt;Programming Clojure&lt;/a&gt; &lt;span class="author"&gt;&lt;em&gt;by Stuart Halloway&lt;/em&gt;&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;Clojure is a functional programming language that runs in the JVM (hence the &amp;#8220;j&amp;#8221;, I guess). This excellent book contains everything you need to know to start (and continue) programming in Clojure from multimethods to infinite sequences, from ways to deal with concurrency to understanding and writing macros. Clojure rocks and so does this book!&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://www.sitepoint.com/books/design1/"&gt;The Principles of Beautiful Web Design&lt;/a&gt; &lt;span class="author"&gt;&lt;em&gt;by Jason Beaird&lt;/em&gt;&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;I bought this book to be able to do a fancier design than putting black text on white background and using ugly textboxes with Times Roman fonts. It has certainly lived up to this goal and it has some very practical advices and links to resources (I particularly liked the chapter about color). Just as its title says, it explains principles rather than implementation details, which is what I was looking for. That said, I still feel I need another book (and a decent amount of practice, of course) to beam me to the level I had planned to reach before buying it. Any suggestions?&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://www.bookdepository.co.uk/book/9780321146533/Test-Driven-Development"&gt;Test-Driven Development By Example&lt;/a&gt; &lt;span class="author"&gt;&lt;em&gt;by Kent Beck&lt;/em&gt;&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;A true classic, I reckon this book is a must-read for anyone aspiring to adhere to TDD or in fact for anyone already doing it at any level of mastery. In the first two chapters two distinct functionalities are developed (the first one, the Money example, in Java, the second, the xUnit example, in Python) by tiny steps using TDD, at each step pondering on the problem at hand and giving an explanation of the chosen solution. The third and final chapter deals with TDD patterns and is an invaluable addition to the first two chapters. Now that I am writing about it I feel like I should reread this book in 2010 (and then probably once every year). Red, green, refactor!&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://pragprog.com/titles/ahptl"&gt;Pragmatic Thinking and Learning&lt;/a&gt; &lt;span class="author"&gt;&lt;em&gt;by Andy Hunt&lt;/em&gt;&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;The fact that I have not finished only goes to show its splendidness, I simply don&amp;#8217;t want it to end yet. (I read this in a Paul Graham essay but I can&amp;#8217;t find it right now). Its subtitle, &amp;#8220;Refactor your wetware&amp;#8221;, is telling: it shows you how to make yourself more productive by harnessing the innate capabilities of your brain and debugging its intrinsic &amp;#8220;bugs&amp;#8221;. I guess it is also a very refreshing read because it is about our mind and its workings and not some dry technical stuff. The stories and anecdotes linked to some of the sections makes it easy to recall the message. In fact, I liked this book so much I created a &lt;a href="http://github.com/balinterdi/twuckoo/"&gt;&amp;#8220;twitter mini-framework&amp;#8221;&lt;/a&gt; and &lt;a href="http://twitter.com/pragthinklearn"&gt;a twitter channel&lt;/a&gt; for the concise version of the advices.&lt;/p&gt;

&lt;h2&gt;Life is not just about stubbing, view helpers and achromatic color schemes&lt;/h2&gt;

&lt;p&gt;On a Christmas evening, I sat down on a comfy sofa with &lt;a href="http://www.amazon.com/Révolutions-J-M-G-Clézio/dp/2070768538"&gt;Révolutions by J.M.G. Le Clézio&lt;/a&gt; in my hand and was totally immersed in it right from page one. I realized I need occasions like this to repeatedly remind myself how much I miss of life if I only ever read technical books. (Sadly, my list of novels I read last year is a lot shorter than the above one but I heartily recommend you &lt;a href="http://www.goodreads.com/book/show/128029.A_Thousand_Splendid_Suns"&gt;A Thousand Splendid Suns by Khaled Hosseini&lt;/a&gt; and &lt;a href="http://www.goodreads.com/book/show/887407.Poisson_D_or"&gt;Poisson d&amp;#8217;or by J.M.G. Le Clézio&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;Any good books you have read?&lt;/h2&gt;

&lt;p&gt;I am also making a (so far, only mental) list of books for this year and would like to hear your opinion, too. So have you read any books lately that you would passionately recommend for others?&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=ECnbWzciVME:SQSwbg1AQyE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=ECnbWzciVME:SQSwbg1AQyE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=ECnbWzciVME:SQSwbg1AQyE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=ECnbWzciVME:SQSwbg1AQyE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/ECnbWzciVME" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2010/01/11/my-tech-book-list-for-2009.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[i15r handles non-english source]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/CD9O2sRg9oU/i15r-works-with-non-english-source.html" />
    <updated>2010-01-08T00:00:00+01:00</updated>
    <id>http://balinterdi.com/2010/01/08/i15r-works-with-non-english-source</id>
    <content type="html">&lt;p&gt;The other day thinking about how &lt;a href="http://github.com/balinterdi/i15r"&gt;i15r&lt;/a&gt; could be improved I realized that there are times when the language of the non-internationalized site is not English (surprise, surprise). Add to this that lots of languages have &amp;#8220;special&amp;#8221; characters, characters that may not be properly found and replaced by the matchers. So I first learned the basics of &lt;a href="http://blog.grayproductions.net/articles/understanding_m17n"&gt;how Ruby handles encodings&lt;/a&gt; (from &lt;a href="http://blog.grayproductions.net/"&gt;James Edward Gray&amp;#8217;s&lt;/a&gt; excellent series) and then adjusted a few matchers to catch those special characters, too. (Note: one can&amp;#8217;t underestimate the utility of a spec suite that covers most of the code)&lt;/p&gt;

&lt;p&gt;The specs pass but I am pretty certain there are some cases where the matchers might not be up to the task. If you come through such a case, please &lt;a href="http://github.com/balinterdi/i15r/issues"&gt;submit a bug report&lt;/a&gt;. Since there has been a huge improvement in &lt;a href="http://blog.grayproductions.net/articles/ruby_19s_string"&gt;string encoding in Ruby 1.9&lt;/a&gt; (basically, strings now have an encoding as opposed to in &lt;a href="http://blog.grayproductions.net/articles/bytes_and_characters_in_ruby_18"&gt;Ruby 1.8&lt;/a&gt;), there might be some cases where strings are properly internationalized using Ruby 1.9 but not with 1.8.&lt;/p&gt;

&lt;p&gt;So if you think this is a valuable addition or just have not tried i15r yet, go get it:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;install.sh &lt;/span&gt;&lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='sh'&gt;&lt;span class='line'&gt;gem install i15r --source http://gemcutter.org
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;



&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=CD9O2sRg9oU:0YWkj8x0xTc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=CD9O2sRg9oU:0YWkj8x0xTc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=CD9O2sRg9oU:0YWkj8x0xTc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=CD9O2sRg9oU:0YWkj8x0xTc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/CD9O2sRg9oU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2010/01/08/i15r-works-with-non-english-source.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[New year, new blog]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/FZtKL4TKUjc/new-year-new-blog.html" />
    <updated>2010-01-04T00:00:00+01:00</updated>
    <id>http://balinterdi.com/2010/01/04/new-year-new-blog</id>
    <content type="html">&lt;p&gt;I guess it all began with &lt;a href="http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html"&gt;this blog post&lt;/a&gt;. I saw that there is another way for composing a blog post than typing it into a textarea with a WYSIWYG interface (which is, by the way, never really WYSIWYG). It also seemed a lot cooler, something a &amp;#8220;real hacker&amp;#8221; would prefer hands down. The decision to switch my blog over to a textarea-free motor has been subconsciously made the time I read that post but the implementation needed a year to be realized. I reckon the final push was to see how easy &lt;a href="http://lackac.hu/2009/11/19/blog-migralas.html"&gt;the migration of the blog&amp;#8217;s content&lt;/a&gt; is.&lt;/p&gt;

&lt;h2&gt;The tools&lt;/h2&gt;

&lt;p&gt;I decided to use &lt;a href="http://github.com/mojombo/jekyll"&gt;Jekyll&lt;/a&gt;, a static-site generator since it integrates nicely with Github and has all the features I need. Being a static-site generator I needed a client-side solution to handle comments. I chose &lt;a href="http://disqus.com/"&gt;Disqus&lt;/a&gt; because that&amp;#8217;s the one I knew and liked but there are &lt;a href="http://intensedebate.com/"&gt;alternatives&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;The process&lt;/h2&gt;

&lt;h3&gt;Content migration&lt;/h3&gt;

&lt;p&gt;I needed continuity and thus migrating the old posts and comments. Fortunately Jekyll includes &lt;a href="http://wiki.github.com/mojombo/jekyll/blog-migrations"&gt;migration scripts for several blog motors&lt;/a&gt;, among them Wordpress, so that was a piece of cake, everything worked out of the box.&lt;/p&gt;

&lt;p&gt;For the comments, I used &lt;a href="http://gist.github.com/261852"&gt;a modified version of Lackac&amp;#8217;s script&lt;/a&gt;, that he so kindly directed my attention to (thank you, Lackac). Clearly it was more work than migrating the posts but nothing to shy away from. (If you plan to switch from Wordpress to Disqus I believe you&amp;#8217;ll be able to use &lt;a href="http://gist.github.com/261852"&gt;the script&lt;/a&gt; with a few minor modifications.)&lt;/p&gt;

&lt;h3&gt;New design&lt;/h3&gt;

&lt;p&gt;For my Wordpress blog, I used a design template that looked ok but was in PHP and was a PITA to modify or to add some styling to. Since I am looking to improve my capabilities as a designer I thought designing my own blog would be a suitable task to get my hands dirty with. I am not concealing the fact that I borrowed ideas from &lt;a href="http://www.briancasel.com/"&gt;several&lt;/a&gt; &lt;a href="http://tom.preston-werner.com/"&gt;blogs&lt;/a&gt; I liked but hey, they say it&amp;#8217;s not a shame to copy good ideas so what&amp;#8217;s wrong with that?&lt;/p&gt;

&lt;h3&gt;Layout, site feed, etc. with Jekyll&lt;/h3&gt;

&lt;p&gt;Have I said I love open source? There is a Jekyll wiki that lists &lt;a href="http://wiki.github.com/mojombo/jekyll/sites"&gt;Jekyll sites&lt;/a&gt; along with a link to their sources so seeing how to set up my blog with Jekyll was quite straightforward. I guess this was still the most time-consuming part of all but I did not really have to think of anything, the steps are well-defined. (Here is the &lt;a href="http://github.com/balinterdi/balinterdi.github.com"&gt;source of my blog&lt;/a&gt; if you&amp;#8217;d like to take a glimpse.)&lt;/p&gt;

&lt;h3&gt;Buying a Github plan to be able to use a non-github domain&lt;/h3&gt;

&lt;p&gt;If you&amp;#8217;d like to host your blog under a custom domain (&lt;a href="http://codigoergosum.com"&gt;http://codigoergosum.com&lt;/a&gt; instead of &lt;a href="http://balinterdi.github.com"&gt;http://balinterdi.github.com&lt;/a&gt;) you&amp;#8217;ll need to buy a Github plan. Starting at 7$/month for the Micro plan it&amp;#8217;s not an insurmountable obstacle, in fact it costs less than the Wordpress hosting I am moving away from.&lt;/p&gt;

&lt;h2&gt;Changing the name&lt;/h2&gt;

&lt;p&gt;Back in the spring of 2008, returning from the &lt;a href="http://www.euruko2008.org/"&gt;European Ruby conference&lt;/a&gt; (and having finished &lt;a href="http://pragprog.com/titles/tpp/the-pragmatic-programmer"&gt;The Pragmatic Programmer&lt;/a&gt; on the train) my mind was buzzing with new ideas and I could not wait to set myself on a craftsman&amp;#8217;s journey.&lt;/p&gt;

&lt;p&gt;I felt I needed a blog immediately. The hard part of course was coming up with a name. Since I felt it was more important to get something going than to idle on finding the perfect one (I guess we can call this agile, can&amp;#8217;t we? :)), I launched &lt;a href="http://bucionrails.com"&gt;http://bucionrails.com&lt;/a&gt;. During the almost two years that have passed since that day I have grown somewhat uncomfortable with that name so I decided to change it. I hope you like &lt;a href="http://en.wikipedia.org/wiki/Descartes"&gt;the new one&lt;/a&gt; :). (I set up a feed redirection with Feedburner to notify you of the feed URL change after 15 days but you could directly subscribe to the &lt;a href="http://feeds.feedburner.com/codigoergosum"&gt;new feed now&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;The end result&lt;/h2&gt;

&lt;p&gt;It felt appropriate to start the new year with a new blog and -to my surprise- the switch was a lot easier than I had thought. I hope you, the faithful readers of my blog, welcome the change and ameliorate it with your precious comments.&lt;/p&gt;

&lt;p&gt;Now I am blogging like a hacker, too!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=FZtKL4TKUjc:FghK0StnQlQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=FZtKL4TKUjc:FghK0StnQlQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=FZtKL4TKUjc:FghK0StnQlQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=FZtKL4TKUjc:FghK0StnQlQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/FZtKL4TKUjc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2010/01/04/new-year-new-blog.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[i15r 0.3.1 is out - now with haml matchers!]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/N5Cf7qoDv8k/i15r-031-is-out-now-with-haml-matchers.html" />
    <updated>2009-12-14T00:00:00+01:00</updated>
    <id>http://balinterdi.com/2009/12/14/i15r-031-is-out-now-with-haml-matchers</id>
    <content type="html">&lt;p&gt;I&amp;#8217;ve just released a new version of the &lt;a href="http://github.com/balinterdi/i15r"&gt;i15r gem&lt;/a&gt; which alleviates the tedious task of internationalizing a Rails site by finding the &amp;#8220;static&amp;#8221; texts and replacing them with I18n message strings.&lt;/p&gt;

&lt;p&gt;The good news -and probably the reason I am writing a blog post about it- is that it can now process &lt;a href="http://haml-lang.com/"&gt;haml&lt;/a&gt; files, too. This must cheer up those who -like me- have come to like haml so much they now use it for their projects. So &lt;a href="http://gemcutter.org/gems/i15r"&gt;go get it&lt;/a&gt; and let me know how it works for you.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=N5Cf7qoDv8k:Qh9PwNjbKgo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=N5Cf7qoDv8k:Qh9PwNjbKgo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=N5Cf7qoDv8k:Qh9PwNjbKgo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=N5Cf7qoDv8k:Qh9PwNjbKgo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/N5Cf7qoDv8k" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2009/12/14/i15r-031-is-out-now-with-haml-matchers.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Rubygems under the hood: hooking into require]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/Pa5Fs4UFj-s/rubygems-under-the-hood-hooking-into-require.html" />
    <updated>2009-10-28T00:00:00+01:00</updated>
    <id>http://balinterdi.com/2009/10/28/rubygems-under-the-hood-hooking-into-require</id>
    <content type="html">&lt;p&gt;(See &lt;a href="http://bucionrails.com/2009/10/20/rubygems-under-the-hood-introduction/"&gt;the introduction&lt;/a&gt; to the series.)&lt;/p&gt;

&lt;p&gt;When you want to pull in a Ruby library, you require it. The library you require has to be on Ruby&amp;#8217;s load path ($LOAD_PATH) in order to succeed. So let&amp;#8217;s see how Rubygems hooks into this process.&lt;/p&gt;

&lt;p&gt;The secret lies in custom_require.rb. You&amp;#8217;ll see a nice comment near the top.&lt;/p&gt;

&lt;blockquote&gt;
When you call &amp;#8220;require &amp;#8216;x&amp;#8217;&amp;#8221;, this is what happens:
  * If the file can be loaded from the existing Ruby loadpath, it is.
  * Otherwise, installed gems are searched for a file that matches.
If it&amp;#8217;s found in gem &amp;#8216;y&amp;#8217;, that gem is activated (added to the loadpath).
&lt;/blockquote&gt;


&lt;p&gt;In fact, that explanation looks so straightforward to me that I doubt if I can add more words to precise it, so let&amp;#8217;s look at the code together:&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;module Kernel
  alias gem_original_require require
  (...)
  def require(path) # :doc:
    gem_original_require path
  rescue LoadError =&amp;gt; load_error
    if load_error.message =~ /#{Regexp.escape path}\z/ and
       spec = Gem.searcher.find(path) then
      Gem.activate(spec.name, &amp;quot;= #{spec.version}&amp;quot;)
      gem_original_require path
    else
      raise load_error
    end
  end
(...)
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Aliasing a method, redefining it and calling the original version from the redefined method is a very familiar pattern if you have read Rails source code (called method chaining).&lt;/p&gt;

&lt;p&gt;So, just as the above description says, if the file can be loaded &amp;#8220;without Rubygems&amp;#8221; it is and Rubygems never comes into the picture. If not, we make sure that the load error comes from the file not found on the load path and then find the gemspec for that file and activate it.&lt;/p&gt;

&lt;p&gt;Activating it adds it to the load path, so we can call the original require safe in the knowledge that it will now succeed and we won&amp;#8217;t get another load error this time around (and go into an infinite loop). Clever, heh?&lt;/p&gt;

&lt;p&gt;This is one of the cases when the code is so simple for a moment I think I could have written it myself. With its &amp;lt;10 lines of code Rubygems is empowered to load a myriad of useful Ruby libraries. Isn&amp;#8217;t this wonderful?&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=Pa5Fs4UFj-s:XP8_C5KkVjE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=Pa5Fs4UFj-s:XP8_C5KkVjE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=Pa5Fs4UFj-s:XP8_C5KkVjE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=Pa5Fs4UFj-s:XP8_C5KkVjE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/Pa5Fs4UFj-s" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2009/10/28/rubygems-under-the-hood-hooking-into-require.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[RubyGems under the hood: Introduction]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/y_1UFTBSt90/rubygems-under-the-hood-introduction.html" />
    <updated>2009-10-20T00:00:00+02:00</updated>
    <id>http://balinterdi.com/2009/10/20/rubygems-under-the-hood-introduction</id>
    <content type="html">&lt;p&gt;I am not sure about you, but one thing I keep bumping into while developing ruby applications is rubygem version conflicts. If you have ever come across &amp;#8220;can&amp;#8217;t activate activesupport (= 2.3.4, runtime) for [], already activated activesupport-2.3.3 for []&amp;#8221; type of errors, you might be sympathetic to the cause.&lt;/p&gt;

&lt;p&gt;Since &lt;a href="http://rubygems.org/"&gt;rubygems&lt;/a&gt; was and is being written by some &lt;a href="http://chadfowler.com"&gt;excellent&lt;/a&gt; &lt;a href="http://richkilmer.blogs.com/"&gt;Ruby&lt;/a&gt; &lt;a href="http://onestepback.org/"&gt;minds&lt;/a&gt; I knew the fault probably lies with me and not with the tool. Being a &lt;a href="http://manifesto.softwarecraftsmanship.org/"&gt;motivated and proud craftsman&lt;/a&gt; I felt like I needed to know my tools and rubygems is probably the number one tool most of us Ruby developers use on a daily basis.&lt;/p&gt;

&lt;p&gt;I intend to write a mini-series of Rubygems posts. A post will be added to the series when I explore some murky corner of rubygems inner mechanics. Some of the time this will come from a particular problem I come across while coding while on other occasions I might just look into the source code and try to understand what a particular piece of code does.&lt;/p&gt;

&lt;p&gt;Now, I realized that when I read on a blog: &amp;#8220;I will go into more detail about X in a forthcoming post&amp;#8221;, it is the surest sign that you will never read about X again. At least not on that very blog. And I am not saying this in a mean way, I think it is very natural for our plans to change (&amp;#8220;evolve&amp;#8221; may sound better) even on the short term. So I am aiming low and hoping to give you more than you expected. (Notice I wrote &amp;#8220;mini-series&amp;#8221; which may just mean a couple of posts.)&lt;/p&gt;

&lt;h2&gt;Do not set your expectations high&lt;/h2&gt;


&lt;p&gt;I am absolutely not a Rubygems expert so please do not be fooled by the &amp;#8220;under the hood&amp;#8221; title. This will not be commensurate to &lt;a href="http://weblog.jamisbuck.org/2006/10/2/under-the-hood-rails-routing-dsl"&gt;Jamis Buck&amp;#8217;s series on Rails routing&lt;/a&gt;. I do not -yet?- have a deep insight and I am not even a contributor to Rubygems.&lt;/p&gt;

&lt;p&gt;The forthcoming :) series is just a humble attempt to gain an understanding of a very important part of the Ruby arsenal. I hope to understand it better by explaining to you how it works and I hope you will understand it better by reading my explanation. And last, but not least, I hope we&amp;#8217;ll both spend less time debugging those tricky issues.&lt;/p&gt;

&lt;p&gt;Having said that, I encourage you to participate in the series. Tell me about a particular problem you had with Rubygems. Correct me if I am wrong. Point me to an article where all this is already explained, and much better. Give feedback so this might evolve to be a discussion rather than an academic lecture. Thank you.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=y_1UFTBSt90:8ThYI4j5_iI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=y_1UFTBSt90:8ThYI4j5_iI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=y_1UFTBSt90:8ThYI4j5_iI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=y_1UFTBSt90:8ThYI4j5_iI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/y_1UFTBSt90" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2009/10/20/rubygems-under-the-hood-introduction.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Cucumber meets Selenium meets Integrity]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/hHk0CDhWOUo/cucumber-meets-selenium-meets-integrity.html" />
    <updated>2009-09-25T00:00:00+02:00</updated>
    <id>http://balinterdi.com/2009/09/25/cucumber-meets-selenium-meets-integrity</id>
    <content type="html">&lt;p&gt;&lt;a href="http://martinfowler.com/articles/continuousIntegration.html" title="Continuous Integration"&gt;Continuous Integration&lt;/a&gt; (CI) is a basic building block of any project done in TDD style. In brief, having a CI server properly set up guarantees that developers can rest assured that the application passes all its tests and can thus be deployed at any moment. It does this by sending some kind of a warning if something is broken so it can be fixed immediately.&lt;/p&gt;

&lt;p&gt;Now I noticed that if a CI server is not in the mix right from the beginning of project, chances are it will never be, that was one of the first things I installed on a new Rails project. My server of choice is &lt;a href="http://integrityapp.com"&gt;Integrity&lt;/a&gt; mostly because it is so easy to set up and quite straightforward to use.&lt;/p&gt;

&lt;p&gt;Ok, so next we need some tests that Integrity will run at each commit and make sure the app can still be built. As a high-level acceptance test framework, I use &lt;a href="http://cukes.info"&gt;Cucumber&lt;/a&gt;, which plays very nicely with &lt;a href="http://seleniumhq.org"&gt;Selenium&lt;/a&gt; for automated in-browser testing. Since nowadays even the most basic web application will have some amount of client-side scripting code (that is, javascript) if you really want to test the features of your application you&amp;#8217;ll need Selenium tests.&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s when matters get a bit more complicated when it comes to integrating these with the Integrity server. Why? Because on the server you usually don&amp;#8217;t have the &amp;#8220;desktop environment&amp;#8221; which is available on the machine you do the development on. By default, you don&amp;#8217;t run a desktop manager and have a graphic display on a server. A tool called &lt;a href="http://linux.about.com/cs/linux101/g/xvfb.htm"&gt;xvfb&lt;/a&gt; comes into a picture that emulate a dumb framebuffer so you can still programs that need a graphic display.&lt;/p&gt;

&lt;p&gt;To have some practical guidance, here&amp;#8217;s what I did on an Ubuntu server to enable all of the above:&lt;/p&gt;

&lt;p&gt;Install java since Selenium runs in the JVM:&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;apt-get install java-common sun-java6-jre&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Install firefox since that&amp;#8217;s what Selenium runs by default and that&amp;#8217;s a very good choice.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;apt-get install apt-get install firefox&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Install X since that&amp;#8217;s what the xvfb launches and Xvfb itself.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;apt-get install xorg xserver-xorg
apt-get install xvfb&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Next I found a &lt;a href="http://wiki.openqa.org/display/SRC/Selenium-RC+and+Continuous+Integration"&gt;wiki&lt;/a&gt; that describes how to launch the Xvfb correctly. Log into the server and do:&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;startx -- `which Xvfb` :1 -screen 0 1024x768x24 2&amp;gt;&amp;amp;1 &amp;gt;/dev/null &amp;amp;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;So Xvfb will run on the DISPLAY :1. So far so good. But something was still not quite right. When integrity launched the test suite that included some Cucumber-Selenium tests I received an error message basically saying that no browser sessions could be started. And the solution to that, in fact, is where this post wants to get at.&lt;/p&gt;

&lt;p&gt;After a decent amount of head-scratching and code mining I realized that the Selenium server starts the browser on the same display where the server itself (the jar file) runs. I have found the relevant code that assembles the command that starts the Selenium server in the selenium-client gem and figured it was not meant to be run in graphic hardware-less environment since I saw no options to define which display it should run on. So as an &lt;a href="http://github.com/balinterdi/selenium-client/commit/37094df174b5c52cb68d041f7dc940e501b3e438"&gt;easy hack I added the hardcoded &amp;#8220;DISPLAY=:1&amp;#8221; before it&lt;/a&gt; and crossed my fingers.&lt;/p&gt;

&lt;p&gt;Bingo, it worked and I had a green build again! What&amp;#8217;s more surprising is that it still runs perfectly on my Macbook so it seems to run in (some) graphical environments, too. It seems a bit strange to me to have found so little information on this subject since Rails, Cucumber, Selenium and CI are all en vogue so it is possible that I missed something obvious and there is an easier way to do all this. I am very eager to hear how others set up their CI to run automated-browser features. Do you use another tool, not Selenium? Do you use a CI server with a monitor?&lt;/p&gt;

&lt;p&gt;Anyway, I certainly hope my hackish solution will prove to be useful for some of you TDD-minded developers out there who run their CI on a simple &amp;lt;name of your favorite provider here&amp;gt; slice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; As &lt;a href="http://lackac.hu"&gt;a fellow developer&lt;/a&gt; and &lt;a href="http://github.com/ph7"&gt;the author of the selenium-client gem himself&lt;/a&gt; pointed out library code is not the place for enviroment specific settings. Rather, it should go into the application&amp;#8217;s code. I guess that leaves the choice of putting it into the code of the application you are building or the configuration of the CI server. This latter seemed more clean to me so I put the following line into config.ru in Integrity&amp;#8217;s directory:&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;env[&amp;quot;DISPLAY&amp;quot;] = &amp;quot;:1&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;There is still something left, though. When integrity -or, to be precise, the selenium process that was launched from integrity- wants to access display :1, it will be denied. You need to explicitly enable local connections by putting &amp;#8220;localhost&amp;#8221; in a file:&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;echo 'localhost' &amp;gt;/etc/X99.cfg&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;, and then using that file as the access records list when you launch the server:&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;xinit -- `which Xvfb` :1 -screen 0 1024x768x24 -auth /etc/X99.cfg 2&amp;gt;&amp;amp;1 &amp;gt;/dev/null &amp;amp;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;(Note that I launch xinit and not startx as before. startx somehow adds another -auth option which messes things up)&lt;/p&gt;

&lt;p&gt;There, that should do it. It works and there is no code where it does not belong.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=hHk0CDhWOUo:Q8LEKRYjYx0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=hHk0CDhWOUo:Q8LEKRYjYx0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=hHk0CDhWOUo:Q8LEKRYjYx0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=hHk0CDhWOUo:Q8LEKRYjYx0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/hHk0CDhWOUo" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2009/09/25/cucumber-meets-selenium-meets-integrity.html</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[A prime example of not eating your own dog food]]></title>
    <link href="http://feedproxy.google.com/~r/codigoergosum/~3/PMvYlhlCDUc/a-prime-example-of-not-eating-your-own-dog-food.html" />
    <updated>2009-07-14T00:00:00+02:00</updated>
    <id>http://balinterdi.com/2009/07/14/a-prime-example-of-not-eating-your-own-dog-food</id>
    <content type="html">&lt;p&gt;I realized how 20th century (plus boring and error-prone) it is to write one&amp;#8217;s invoices by hand. So I went looking for an invoicing application. My expectations were quite low: I wanted one which can be used from my MacBook, has some basic functions that cut down on typing (e.g a client &amp;#8220;database&amp;#8221;), has a decent design and UI, can make out invoices in different currencies and did not cost more than ~$100.&lt;/p&gt;

&lt;p&gt;It seemed like I have found &lt;a href="http://www.native.hu"&gt;one&lt;/a&gt;, which, though it had several minor bugs, seemed acceptable, so I purchased the Basic version. Everything went reasonably well until I had to make out my first invoice in euros. It turned out that the Basic version can only make invoices in Hungarian forints in spite of having a couple of other functionalities (e.g set the VAT rate to 0% automatically on invoices made out to EU companies) which made me think it could make it in euros, too.&lt;/p&gt;

&lt;p&gt;Ok, so accounting hell got me again. I sighed and asked the &lt;a href="http://www.awasoft.hu/"&gt;company&lt;/a&gt; how much it would cost to have this funcionality. I was informed I had to buy the upgrade to the Business version which costs ~$120 more, roughly the double of the original price I paid! That was too much to take, so I went looking for another invoicing application. After all, it should not be an insurmountable task to write such an app, I murmured to myself.&lt;/p&gt;

&lt;p&gt;I did find a &lt;a href="http://lessaccounting.com"&gt;couple of&lt;/a&gt; &lt;a href="http://billingsapp.com"&gt;very good&lt;/a&gt; applications which even overdo what I want them to accomplish. However, the Hungarian homologue of the IRS basically shuts out any foreign competitors by regulating very heavily which conditions must be fulfilled by an invoicing application for a Hungarian company to be able to use it. Bummer.&lt;/p&gt;

&lt;p&gt;&amp;#8220;There is still a glimmer of hope.&amp;#8221; - I thought. I checked the Hungarian scene still thinking it could not be that difficult to meet my expectations. Well, apparently I was wrong. The &lt;a href="http://szamlazz.hu"&gt;ones&lt;/a&gt; &lt;a href="http://cipo.hu"&gt;I&lt;/a&gt; &lt;a href="https://symbion.eu/"&gt;found&lt;/a&gt; are either overcomplicated to use, look like home pages in the 80s or are way too expensive. Sometimes all of these. So I put off the challenge of finding an acceptable piece of software and got back of writing invoices manually.&lt;/p&gt;

&lt;p&gt;Now you might wonder where &lt;a href="http://en.wikipedia.org/wiki/Eating_one%27s_own_dog_food"&gt;the dog food&lt;/a&gt; is in the story. Well, today I received the invoice from the company of my purchase of the Basic version of the application. It was written manually on an invoice sheet :) That&amp;#8217;s tantamount of Steve Jobs using a PC with Windows Vista.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=PMvYlhlCDUc:a3a3S3ludYA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=PMvYlhlCDUc:a3a3S3ludYA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?i=PMvYlhlCDUc:a3a3S3ludYA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/codigoergosum?a=PMvYlhlCDUc:a3a3S3ludYA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/codigoergosum?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/codigoergosum/~4/PMvYlhlCDUc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://balinterdi.com/2009/07/14/a-prime-example-of-not-eating-your-own-dog-food.html</feedburner:origLink></entry>
  
</feed>
