<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>http://www.philcalcado.com/</id>
  <title>Phil Calcado Blog Syndication</title>
  <updated>2012-06-30T22:00:00Z</updated>
  <link rel="alternate" href="http://www.philcalcado.com/"/>
  <link rel="self" href="http://www.philcalcado.com/atom.xml"/>
  <author>
    <name>Phil Calcado</name>
    <uri>http://philcalcado.com</uri>
  </author>
  <entry>
    <id>tag:www.philcalcado.com,2012-07-01:/2012/07/01/annoying_rspec_dynamic_scoping_in_example_groups.html</id>
    <title type="html">Annoying RSpec: Dynamic Scope</title>
    <published>2012-06-30T22:00:00Z</published>
    <updated>2012-07-01T17:29:32Z</updated>
    <link rel="alternate" href="http://www.philcalcado.com/2012/07/01/annoying_rspec_dynamic_scoping_in_example_groups.html"/>
    <content type="html">&lt;p&gt;At &lt;a href="http://bitly.com/work-at-soundcloud"&gt;SoundCloud&lt;/a&gt;, we use a fair
chunk of different languages, but most of our current code base uses
Ruby; usually web apps built with Rails/Sinatra and workers using
EventMachine.&lt;/p&gt;

&lt;p&gt;Ruby has a very mature test framework called RSpec. I really like it,
even used it through JRuby to test Java code. There are a few things
with the way some people use the framework which really puts me off,
though. Let's discuss some of them in a series of posts.&lt;/p&gt;

&lt;h2&gt;Scoping Rules&lt;/h2&gt;

&lt;p&gt;A while back I wrote on &lt;a href="http://philcalcado.com/2011/12/29/read_the_dinossaurs.html"&gt;why reading &lt;em&gt;classic&lt;/em&gt; computer science and
software engineering books is
important&lt;/a&gt;. One
theme you are going to see over and over on these books is the issue
of scoping.&lt;/p&gt;

&lt;p&gt;There are many different ways to implement scoping in a system, the
two most common strategies are &lt;strong&gt;lexical&lt;/strong&gt; and
&lt;strong&gt;dynamic&lt;/strong&gt;. Summarising a very long discussion, &lt;em&gt;scope&lt;/em&gt; is where the
runtime and/or compiler should look to check if something you are
trying to use (e.g. a variable identifier) is valid (i.e. it is
&lt;em&gt;bound&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Ruby has lexical scope, which pretty much means that we must declare
variables somewhere before using them. In the code below, &lt;em&gt;user&lt;/em&gt; is
not a valid variable, as it isn't bound to anything:&lt;/p&gt;

&lt;pre&gt;
describe &lt;span style="color: #ffcc66;"&gt;Group&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
 it &lt;span style="color: #99cc99;"&gt;'adds user to the group'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
   group = &lt;span style="color: #ffcc66;"&gt;Group&lt;/span&gt;.new
   group &amp;lt;&amp;lt; user
   group.members.should == [user]
 &lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;We can fix this easibly by doing:&lt;/p&gt;

&lt;pre&gt;
describe &lt;span style="color: #ffcc66;"&gt;Group&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
  it &lt;span style="color: #99cc99;"&gt;'adds user to the group'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
    user = &lt;span style="color: #ffcc66;"&gt;User&lt;/span&gt;.new
    group = &lt;span style="color: #ffcc66;"&gt;Group&lt;/span&gt;.new
    group &amp;lt;&amp;lt; user

    group.should include(user)
    group.members.should have(1).item
  &lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;RSpec's DSL has &lt;a href="http://bit.ly/LZ08Ih"&gt;a useful construct called let&lt;/a&gt;
which lets you define variables you want to use in more than one
example &#8212;just like one would use an instance variable in a non-DSL
framework like JUnit. We can use it like this:&lt;/p&gt;

&lt;pre&gt;
describe &lt;span style="color: #ffcc66;"&gt;Group&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
  let(&lt;span style="color: #99cc99;"&gt;:user&lt;/span&gt;) { &lt;span style="color: #ffcc66;"&gt;User&lt;/span&gt;.new }

  it &lt;span style="color: #99cc99;"&gt;'adds user to the group'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
    group = &lt;span style="color: #ffcc66;"&gt;Group&lt;/span&gt;.new
    group &amp;lt;&amp;lt; user

    group.members.should == [user]
  &lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;

  it &lt;span style="color: #99cc99;"&gt;'removes user from group'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
    group = &lt;span style="color: #ffcc66;"&gt;Group&lt;/span&gt;.new
    group &amp;lt;&amp;lt; user

    group.remove!(user)

    group.members.should == []
  &lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;Some other languages provide &lt;em&gt;dynamic scope&lt;/em&gt;, the classic examples are
from the LISP languages, including Common Lisp (but not Scheme). Here
is an example in Emacs Lisp (ELisp):&lt;/p&gt;

&lt;pre&gt;

&lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;&lt;span style="color: #cc99cc;"&gt;defun&lt;/span&gt; &lt;span style="color: #99cccc;"&gt;is-expected?&lt;/span&gt; &lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;other-thing&lt;span style="color: #7f7f7f;"&gt;)&lt;/span&gt;
  &lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;eql the-thing other-thing&lt;span style="color: #7f7f7f;"&gt;))&lt;/span&gt;

&lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;set 'the-thing 999&lt;span style="color: #7f7f7f;"&gt;)&lt;/span&gt;
&lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;is-expected? 666&lt;span style="color: #7f7f7f;"&gt;)&lt;/span&gt; &lt;span style="color: #969896; font-style: italic;"&gt;;; &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;returns false
&lt;/span&gt;&lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;is-expected? 999&lt;span style="color: #7f7f7f;"&gt;)&lt;/span&gt; &lt;span style="color: #969896; font-style: italic;"&gt;;; &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;returns true
&lt;/span&gt;the-thing &lt;span style="color: #969896; font-style: italic;"&gt;;; &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;returns 999
&lt;/span&gt;

&lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;&lt;span style="color: #cc99cc;"&gt;let&lt;/span&gt; &lt;span style="color: #7f7f7f;"&gt;((&lt;/span&gt;the-thing 666&lt;span style="color: #7f7f7f;"&gt;))&lt;/span&gt;
  &lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;is-expected? 666&lt;span style="color: #7f7f7f;"&gt;)&lt;/span&gt;  &lt;span style="color: #969896; font-style: italic;"&gt;;; &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;returns true
&lt;/span&gt;  &lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;is-expected? 999&lt;span style="color: #7f7f7f;"&gt;))&lt;/span&gt; &lt;span style="color: #969896; font-style: italic;"&gt;;; &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;returns false
&lt;/span&gt;the-thing &lt;span style="color: #969896; font-style: italic;"&gt;;; &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;returns 999
&lt;/span&gt;
&lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;&lt;span style="color: #cc99cc;"&gt;let&lt;/span&gt; &lt;span style="color: #7f7f7f;"&gt;((&lt;/span&gt;the-thing 0&lt;span style="color: #7f7f7f;"&gt;))&lt;/span&gt;
  &lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;is-expected? 666&lt;span style="color: #7f7f7f;"&gt;)&lt;/span&gt;  &lt;span style="color: #969896; font-style: italic;"&gt;;; &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;returns false
&lt;/span&gt;  &lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;is-expected? 999&lt;span style="color: #7f7f7f;"&gt;))&lt;/span&gt; &lt;span style="color: #969896; font-style: italic;"&gt;;; &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;returns false
&lt;/span&gt;the-thing &lt;span style="color: #969896; font-style: italic;"&gt;;; &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;returns 999
&lt;/span&gt;
&lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;&lt;span style="color: #cc99cc;"&gt;defun&lt;/span&gt; &lt;span style="color: #99cccc;"&gt;multiply-and-compare&lt;/span&gt; &lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;what&lt;span style="color: #7f7f7f;"&gt;)&lt;/span&gt;
  &lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;is-expected? &lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;* what 100&lt;span style="color: #7f7f7f;"&gt;)))&lt;/span&gt;

&lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;&lt;span style="color: #cc99cc;"&gt;let&lt;/span&gt; &lt;span style="color: #7f7f7f;"&gt;((&lt;/span&gt;the-thing 100&lt;span style="color: #7f7f7f;"&gt;))&lt;/span&gt;
  &lt;span style="color: #7f7f7f;"&gt;(&lt;/span&gt;multiply-and-compare 1&lt;span style="color: #7f7f7f;"&gt;))&lt;/span&gt; &lt;span style="color: #969896; font-style: italic;"&gt;;; &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;returns true
&lt;/span&gt;the-thing &lt;span style="color: #969896; font-style: italic;"&gt;;; &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;returns 999
&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;The value of &lt;em&gt;the-thing&lt;/em&gt; depends on when it was invoked. This is an
extreme case of temporal coupling, very similar to the problems caused
by using global variables.&lt;/p&gt;

&lt;p&gt;Nevertheless, dynamic scope can be really useful. It is often a great tool
when you need to implement embedded DSLs. To use it, though, &lt;a href="http://bit.ly/O7h3eg"&gt;one has
to adopt many conventions and tricks to avoid losing
sanity&lt;/a&gt;; and as Doug Hoyte discusses in &lt;a href="http://amzn.to/IMMkNO"&gt;his
awesome Let Over Lambda book&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Dynamic scoping used to be a defining feature of lisp but has, since
COMMON LISP, been almost completely replaced by lexical scope. Since
lexical scoping enables things like lexical closures (which we
examine shortly), as well as more effective compiler optimisations,
the superseding of dynamic scope is mostly seen as a good
thing. However, the designers of COMMON LISP have left us a very
transparent window into the world of dynamic scoping, now
acknowledged for what it really is: special.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;And even Emacs Lisp, &lt;a href="http://bit.ly/MALb1Z"&gt;in its last version&lt;/a&gt;, has
lexical scoping.&lt;/p&gt;

&lt;h2&gt;Dynamic Scoping in RSpec&lt;/h2&gt;

&lt;p&gt;So how is this related to RSpec usage? Well, turns out that RSpec's
embedded DSL provides an equivalent of dynamic binding, and pretty
much every Ruby project I was part of uses this "feature".&lt;/p&gt;

&lt;p&gt;Here is an example:&lt;/p&gt;

&lt;pre&gt;
&lt;span style="color: #969896; font-style: italic;"&gt;# &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;event_consumer_examples.rb
&lt;/span&gt;shared_examples_for &lt;span style="color: #99cc99;"&gt;'event consumer'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
  it &lt;span style="color: #99cc99;"&gt;'raises error if asked to consume invalid event'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
    expect { subject.consume(invalid_event) }.to raise_error
  &lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;

  it &lt;span style="color: #99cc99;"&gt;'consumes valid event'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
    expect { subject.consume(valid_event) }.to_not raise_error
  &lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;

&lt;span style="color: #969896; font-style: italic;"&gt;# &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;user_creation_consumer_spec.rb
&lt;/span&gt;describe &lt;span style="color: #ffcc66;"&gt;UserCreationConsumer&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
  let(&lt;span style="color: #99cc99;"&gt;:invalid_event&lt;/span&gt;) { &lt;span style="color: #ffcc66;"&gt;SpamEvent&lt;/span&gt;.new  }
  let(&lt;span style="color: #99cc99;"&gt;:valid_event&lt;/span&gt;) { &lt;span style="color: #ffcc66;"&gt;UserEvent&lt;/span&gt;.new  }

  it_should_behave_like &lt;span style="color: #99cc99;"&gt;'event consumer'&lt;/span&gt;
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;

&lt;span style="color: #969896; font-style: italic;"&gt;# &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;spam_report_consumer_spec.rb
&lt;/span&gt;describe &lt;span style="color: #ffcc66;"&gt;SpamReportedConsumer&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
  let(&lt;span style="color: #99cc99;"&gt;:invalid_event&lt;/span&gt;) { &lt;span style="color: #ffcc66;"&gt;UserEvent&lt;/span&gt;.new  }
  let(&lt;span style="color: #99cc99;"&gt;:valid_event&lt;/span&gt;) { &lt;span style="color: #ffcc66;"&gt;SpamEvent&lt;/span&gt;.new  }

  it_should_behave_like &lt;span style="color: #99cc99;"&gt;'event consumer'&lt;/span&gt;
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;The shared examples in the first snippet depend on two symbols,
&lt;em&gt;invalid_event&lt;/em&gt; and &lt;em&gt;valid_event&lt;/em&gt;. How these symbols are defined
depends on when &lt;em&gt;it_should_behave_like 'event consumer'&lt;/em&gt; is called.&lt;/p&gt;

&lt;p&gt;To make matters worse, it is very rare that a test case is as simple
as the minimal example above. Often you see things like this:&lt;/p&gt;

&lt;pre&gt;
&lt;span style="color: #969896; font-style: italic;"&gt;# &lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;user_creation_consumer_spec.rb
&lt;/span&gt;describe &lt;span style="color: #ffcc66;"&gt;UserCreationConsumer&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
  let(&lt;span style="color: #99cc99;"&gt;:transaction_type&lt;/span&gt;) { stub(&lt;span style="color: #99cc99;"&gt;'transaction type'&lt;/span&gt;)  }
  let(&lt;span style="color: #99cc99;"&gt;:invalid_event&lt;/span&gt;)    { &lt;span style="color: #ffcc66;"&gt;SpamEvent&lt;/span&gt;.new  }
  let(&lt;span style="color: #99cc99;"&gt;:valid_event&lt;/span&gt;)      { &lt;span style="color: #ffcc66;"&gt;UserEvent&lt;/span&gt;.new  }
  let(&lt;span style="color: #99cc99;"&gt;:observer&lt;/span&gt;)         { &lt;span style="color: #ffcc66;"&gt;FakeObserver&lt;/span&gt;.new  }
  let(&lt;span style="color: #99cc99;"&gt;:event&lt;/span&gt;)            { stub(&lt;span style="color: #99cc99;"&gt;'some event'&lt;/span&gt;)  }

  it_should_behave_like &lt;span style="color: #99cc99;"&gt;'event consumer'&lt;/span&gt;
  it_should_behave_like &lt;span style="color: #99cc99;"&gt;'observable'&lt;/span&gt;
  it_should_behave_like &lt;span style="color: #99cc99;"&gt;'component'&lt;/span&gt;

  it &lt;span style="color: #99cc99;"&gt;'logs the user creation somewhere'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
    &lt;span style="color: #969896; font-style: italic;"&gt;#&lt;/span&gt;&lt;span style="color: #999999; font-style: italic;"&gt;...
&lt;/span&gt;  &lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;&lt;/pre&gt;


&lt;p&gt;Now, if I want to do some simple refactoring, like renaming the
&lt;em&gt;:event&lt;/em&gt; binding, I have to go through all the example groups and see
what uses that.&lt;/p&gt;

&lt;p&gt;Eventually, my tests will become so hard to maintain I
will pretty much wrap each &lt;em&gt;it_should_behave_like&lt;/em&gt; block into its own
&lt;em&gt;describe&lt;/em&gt; or &lt;em&gt;context&lt;/em&gt; block, and maybe define some naming
conventions around variables consumed by a given shared example. This
is exactly the same kind of overhead we need to apply when using
dynamic scope, as described by the article linked above.&lt;/p&gt;

&lt;h2&gt;Making it Explicit&lt;/h2&gt;

&lt;p&gt;When I first had to work on a big code base with tests relying on
dynamic scope, I spent a couple of hours thinking about how to bypass
what I saw as a limitation of RSpec. Then I realised something: &lt;strong&gt;even
though you cannot make what you define in your spec not visible by the
shared group, you can be explicit about what you pass to the argument
groups&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can pass an initialisation block, which will be executed before
the specs on that shared group. This doesn't require any change to the
shared group itself, we just need to change our specs a bit:&lt;/p&gt;

&lt;pre&gt;
describe &lt;span style="color: #ffcc66;"&gt;UserCreationConsumer&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
  it_should_behave_like &lt;span style="color: #99cc99;"&gt;'event consumer'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
    let(&lt;span style="color: #99cc99;"&gt;:invalid_event&lt;/span&gt;) { &lt;span style="color: #ffcc66;"&gt;SpamEvent&lt;/span&gt;.new  }
    let(&lt;span style="color: #99cc99;"&gt;:valid_event&lt;/span&gt;) { &lt;span style="color: #ffcc66;"&gt;UserEvent&lt;/span&gt;.new  }
  &lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;

describe &lt;span style="color: #ffcc66;"&gt;SpamReportedConsumer&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
  it_should_behave_like &lt;span style="color: #99cc99;"&gt;'event consumer'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
    let(&lt;span style="color: #99cc99;"&gt;:invalid_event&lt;/span&gt;) { &lt;span style="color: #ffcc66;"&gt;UserEvent&lt;/span&gt;.new  }
    let(&lt;span style="color: #99cc99;"&gt;:valid_event&lt;/span&gt;) { &lt;span style="color: #ffcc66;"&gt;SpamEvent&lt;/span&gt;.new  }
  &lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;Or you can declare your shared group in a way that receives
parameters, just like any other function call would:&lt;/p&gt;

&lt;pre&gt;
shared_examples_for &lt;span style="color: #99cc99;"&gt;'event consumer'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt; |valid_event, invalid_event|
  it &lt;span style="color: #99cc99;"&gt;'raises error if asked to consume invalid event'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
    expect { subject.consume(invalid_event) }.to raise_error
  &lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;

  it &lt;span style="color: #99cc99;"&gt;'consumes valid event'&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
    expect { subject.consume(valid_event) }.to_not raise_error
  &lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;

describe &lt;span style="color: #ffcc66;"&gt;UserCreationConsumer&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
  it_should_behave_like &lt;span style="color: #99cc99;"&gt;'event consumer'&lt;/span&gt;, &lt;span style="color: #ffcc66;"&gt;UserEvent&lt;/span&gt;.new, &lt;span style="color: #ffcc66;"&gt;SpamEvent&lt;/span&gt;.new
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;

describe &lt;span style="color: #ffcc66;"&gt;SpamReportedConsumer&lt;/span&gt; &lt;span style="color: #cc99cc;"&gt;do&lt;/span&gt;
  it_should_behave_like &lt;span style="color: #99cc99;"&gt;'event consumer'&lt;/span&gt;, &lt;span style="color: #ffcc66;"&gt;SpamEvent&lt;/span&gt;.new, &lt;span style="color: #ffcc66;"&gt;UserEvent&lt;/span&gt;.new
&lt;span style="color: #cc99cc;"&gt;end&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;The resulting code not only is smaller, but easier to follow and refactor.&lt;/p&gt;

&lt;p&gt;I am not sure why people don't use this more often, maybe because
people are so used to everything being global in Rails
that they don't think too much of it.&lt;/p&gt;
</content>
    <summary type="html">Please stop using dynamic scoping for shared examples</summary>
  </entry>
  <entry>
    <id>tag:www.philcalcado.com,2011-12-29:/2011/12/29/read_the_dinossaurs.html</id>
    <title type="html">Read The Dinossaurs!</title>
    <published>2011-12-28T23:00:00Z</published>
    <updated>2011-12-30T15:52:19Z</updated>
    <link rel="alternate" href="http://www.philcalcado.com/2011/12/29/read_the_dinossaurs.html"/>
    <content type="html">&lt;p&gt;I just finished reading a &lt;a href="http://bit.ly/vc06HT"&gt;review for The Mythical Man-Month on Jaco
Pretorius blog&lt;/a&gt;. This post started as a comment
there but... you know how it works.&lt;/p&gt;

&lt;p&gt;I would recommend to read his review in full, but here are the parts
which caught my attention:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Apart from the examples being so outdated I&#8217;ve only really heard of
one or two of them (in history books), the entire book reads like a
dinosaur.  [...]&lt;/p&gt;

&lt;p&gt;So apart from the examples being from the stone age and the diction
being long-winded, I tried to take a step back and consider why the
concepts being discussed seem out of place.&lt;/p&gt;

&lt;p&gt;It comes down to Agile development. Pretty much all the concepts and
possible solutions introduced are superseded in one way or another by
Agile. [...]&lt;/p&gt;

&lt;p&gt;This book seems to advocate the incredibly outdated software
life-cycle [...] Those days are behind us (hopefully).&lt;/p&gt;

&lt;p&gt;I realize that at the time this book was written this was pretty
much standard practice, I simply fail to see how it still has any
relevance today. [...]&lt;/p&gt;

&lt;p&gt;To be fair, some of the later chapters are a bit more modern
[...] but arguing about whether or not Ada will be the next big
programming language and whether or not Object-Orientated Programming
will become mainstream really doesn&#8217;t appeal to me. Software
development is simply a field which changes too quickly &#8211; a book
which was written 10 years ago would be completely out of date, never
mind one which was written 36 years ago!&lt;/p&gt;

&lt;p&gt;I think a large part of the popular appeal of this book is
unfortunately simply the nostalgia value. From a practical and
relevancy perspective it offers very little.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;If you follow this blog, you probably expect me to have some strong
opinions about the points Jaco raises, as &lt;a href="http://bit.ly/tK3PtB"&gt;I am a bit of a book worm
myself&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; I don't know Jaco; everything I write here is based on
  my interpretation of the review he posted and my assumptions can be
  just plain wrong.&lt;/p&gt;

&lt;h2&gt;It's about the mindset&lt;/h2&gt;

&lt;p&gt;It seems to me that much of Jaco's reaction is not to the ideas
contained in the book, but to the "old" feeling of everything.&lt;/p&gt;

&lt;p&gt;I used to buy a lot of books on technology. At some stage I gave up
and decided that for frameworks, languages and tools I would read the book on the
(excellent) &lt;a href="http://bit.ly/v84Tkh"&gt;Safari Books Online&lt;/a&gt;. I would only
buy books where technology was used as a medium, not the goal. It's
like the old, often &lt;a href="http://bit.ly/t3cvY4"&gt;misquoted as Dijkstra's&lt;/a&gt;,
quote:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;We need to do away with the myth that computer science is about
computers. Computer science is no more about computers than
astronomy is about telescopes, biology is about microscopes or
chemistry is about beakers and test tubes. Science is not about
tools, it is about how we use them and what we find out when we do.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&#8212;&lt;a href="http://bit.ly/tC6E8J"&gt;Michael R. Fellows and Ian Parberr, SIGACT trying to get children
excited about CS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many of the most important books for both computer science and
software engineering use "outdated" technology
(e.g. &lt;a href="http://amzn.to/vBUUKp"&gt;SICP&lt;/a&gt;, &lt;a href="http://amzn.to/sBkCyJ"&gt;TAOCP&lt;/a&gt;,
&lt;a href="http://amzn.to/tGcHGk"&gt;Refactoring&lt;/a&gt;, &lt;a href="http://amzn.to/vXWbZ0"&gt;OOSC&lt;/a&gt;,
&lt;a href="http://amzn.to/rMTPHi"&gt;Object-Oriented Heuristics&lt;/a&gt;, &lt;a href="http://amzn.to/unzci4"&gt;GOF's
Patterns&lt;/a&gt;, &lt;a href="http://amzn.to/tgxf8c"&gt;POEAA&lt;/a&gt;...)
and they are still relevant because the good ideas are still
applicable.&lt;/p&gt;

&lt;p&gt;Jaco asks a commenter to provide specific examples of how Brooks' essays
originated many of the practices in this industry; I would be
surprised if I find a recent book on software management that doesn't
base its content on Brooks' work, even if transitively.&lt;/p&gt;

&lt;p&gt;It is surely much more pragmatic to read a book with "Agile something"
on the cover, drinking from the derived  work. This is good enough for
most practitioners.&lt;/p&gt;

&lt;p&gt;If you don't understand what the situation was before that, though,
agile becomes just another cargo cult (I'd say it's been one for quite
a while). Knowing where our techniques come from &lt;strong&gt;is not nostalgia,
it's History.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But I can see how people get frustrated with old, "classic"
material. Authors use their current environment to illustrate how to
apply the principles they had in mind. Some literature, like the
&lt;a href="http://bit.ly/uBSSC9"&gt;Agile Manifesto and its practices&lt;/a&gt; try to be
smarter by not mentioning specific technology; but this is not the
norm; even for books published today.&lt;/p&gt;

&lt;p&gt;There is always plenty of demand for books using some technology,
even if the actual content is just recycled. In 2002, Uncle Bob
released a book called &lt;a href="http://amzn.to/s1bOjl"&gt;"Agile Software Development, Principles,
Patterns, and Practices"&lt;/a&gt;. I found it great,
and when Amazon recommended me what looked like &lt;a href="http://amzn.to/rIRD96"&gt;a new edition of
it&lt;/a&gt; I placed my order immeditaly.&lt;/p&gt;

&lt;p&gt;What i didn't realise until I got my copy was that it has pretty much
no difference to the first edition. The ideas, patterns... all
important stuff was just the same, except that they used another
language in the examples.&lt;/p&gt;

&lt;p&gt;I surely prefer what was done with &lt;a href="http://amzn.to/s3dwgQ"&gt;Domain-Driven
Design&lt;/a&gt;. The book itself uses Java to
illustrate its ideas, but it doesn't use more than the basic features
of a class-based object system. Some authors then published books
mapping the ideas to actual technology stacks, like
&lt;a href="http://amzn.to/tfJQEy"&gt;'enterprise' Java&lt;/a&gt; and &lt;a href="http://amzn.to/sqjplz"&gt;.Net&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Outdated? Really?&lt;/h2&gt;

&lt;p&gt;Jaco works for ThoughtWorks. &lt;a href="http://bit.ly/teE5fj"&gt;I was with them for four
years&lt;/a&gt; (I don't think we overlapped), and a
lot of my time there was spent on recruitment.&lt;/p&gt;

&lt;p&gt;One day, I was interviewing a candidate for a development position. He
submitted his answer to the coding challenge in JavaScript, and I was
interested in how he coordinated multiple events happening on the
browser window --it was a very nice animation.&lt;/p&gt;

&lt;p&gt;As he was speaking, the technique sounded familiar and I asked a
tricky question: &lt;em&gt;"Sounds cool; did you invent this?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;He was young and never did anything that wasn't JavaScript before,
so I expected to hear a proud &lt;em&gt;yes&lt;/em&gt;. I was surprised when he said &lt;em&gt;"Oh,
not at all. This is the kinda stuff they used in old
video-games"&lt;/em&gt;. What he had was, essentially, &lt;a href="http://bit.ly/rTsQPS"&gt;a port of a very
old-school, single-threaded game loop&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Outdated&lt;/em&gt; techniques may not be useful in our mainstream
&lt;em&gt;enterprisey&lt;/em&gt; world, but a good developer needs to learn about them so
that they can at least know what to Google for. The limitations of
browsers, mobile devices, big data platforms and so many &lt;em&gt;cool tech&lt;/em&gt;
are not that different from the limitations previous generations had
to deal with. Again, it's History and you either learn from it or
repeat the same mistakes.&lt;/p&gt;

&lt;h2&gt;Different opinions are good&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://amzn.to/vUtUPn"&gt;Fred Brooks released a new book recently&lt;/a&gt;, it
got a lot of attention back then and &lt;a href="http://bit.ly/tc80k4"&gt;I read it as soon ad it was
out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think people will be disappointed to know that his opinions
haven't changed much over the past decades. It is still very much
based on engineering and architecture (Brooks is an amateur
architect). I am very sure that this has to do with the fact that
Brooks is not like most of us, working for a company writing web
apps. His perception of the field is different. That doesn't mean,
though, that I cannot learn from him. His words on design consistency
and trade-offs are really inspiring.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://bit.ly/u0EoBu"&gt;We talked about this topic a while back&lt;/a&gt; and,
as I said then, I try to not let my limited vision of the development
world get in the way when I am reading a text by someone who doesn't
share the same tiny corner with me.&lt;/p&gt;

&lt;p&gt;I never engineered a computer architecture or wrote an operating
system. No software developed by my teams was ever considered &lt;a href="http://bit.ly/tdEEpM"&gt;&lt;em&gt;"to be
one of the most successful computers in history, influencing computer
design for years to come"&lt;/em&gt;&lt;/a&gt;; so when someone on
his position writes something I am eager to read it; even if it is
not directly applicable to my current situation.&lt;/p&gt;
</content>
    <summary type="html">It is not nostalgia, it's History.</summary>
  </entry>
  <entry>
    <id>tag:www.philcalcado.com,2011-11-07:/2011/11/07/berlin_clojure_user_group_better_functional_design_through_tdd.html</id>
    <title type="html">Better Functional Design Through TDD - Slides</title>
    <published>2011-11-06T23:00:00Z</published>
    <updated>2011-11-07T15:20:09Z</updated>
    <link rel="alternate" href="http://www.philcalcado.com/2011/11/07/berlin_clojure_user_group_better_functional_design_through_tdd.html"/>
    <content type="html">&lt;p&gt;&lt;a href="http://philcalcado.com/2011/10/08/on_the_testing_in_clojure_debate.html"&gt;As mentioned before&lt;/a&gt;, last week I gave a presentation to the &lt;a href="http://www.meetup.com/Clojure-Berlin"&gt;Clojure Berlin Meetup&lt;/a&gt; on how
Test-Driven Development can help achieving better design in functional
languages. Slides here:&lt;/p&gt;

&lt;div style="width:425px" id="__ss_9996738"&gt; &lt;strong
style="display:block;margin:12px 0 4px"&gt;&lt;a
href="http://www.slideshare.net/pcalcado/better-functional-design-through-tdd"
title="Better Functional Design through TDD" target="_blank"&gt;Better
Functional Design through TDD&lt;/a&gt;&lt;/strong&gt; &lt;iframe
src="http://www.slideshare.net/slideshow/embed_code/9996738"
width="425" height="355" frameborder="0" marginwidth="0"
marginheight="0" scrolling="no"&gt;&lt;/iframe&gt; &lt;div style="padding:5px 0
12px"&gt; View more &lt;a href="http://www.slideshare.net/"
target="_blank"&gt;presentations&lt;/a&gt; from &lt;a
href="http://www.slideshare.net/pcalcado" target="_blank"&gt;Phil
Cal&#231;ado&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;


&lt;p&gt;This is a theme I want to explore more, so expect new posts soon!&lt;/p&gt;
</content>
    <summary type="html">Slides from the presentation</summary>
  </entry>
  <entry>
    <id>tag:www.philcalcado.com,2011-10-29:/2011/10/29/railscamp_hamburd_2011_what_i_have_learnt_working_with_startups.html</id>
    <title type="html">Slides: What I Have Learnt Working With Startups</title>
    <published>2011-10-28T22:00:00Z</published>
    <updated>2011-10-29T14:17:28Z</updated>
    <link rel="alternate" href="http://www.philcalcado.com/2011/10/29/railscamp_hamburd_2011_what_i_have_learnt_working_with_startups.html"/>
    <content type="html">&lt;p&gt;I am in Hamburg for the awesome &lt;a href="http://railscamp-hamburg.de"&gt;RailsCamp Hamburg
2011&lt;/a&gt;. Here are the slides from my presentation on startup culture vs. tech
debt:&lt;/p&gt;

&lt;div style="width:425px" id="__ss_9936763"&gt; &lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/pcalcado/what-i-have-learnt-working-with-startups" title="what i have learnt working with startups." target="_blank"&gt;what i have learnt working with startups.&lt;/a&gt;&lt;/strong&gt; &lt;iframe src="http://www.slideshare.net/slideshow/embed_code/9936763" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"&gt;&lt;/iframe&gt; &lt;div style="padding:5px 0 12px"&gt; View more &lt;a href="http://www.slideshare.net/" target="_blank"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/pcalcado" target="_blank"&gt;Phil Cal&#231;ado&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;

</content>
    <summary type="html">Slides from RailsCamp Hamburg 2011</summary>
  </entry>
  <entry>
    <id>tag:www.philcalcado.com,2011-10-08:/2011/10/08/on_the_testing_in_clojure_debate.html</id>
    <title type="html">On The Testing In Clojure Debate</title>
    <published>2011-10-07T22:00:00Z</published>
    <updated>2011-10-09T12:03:11Z</updated>
    <link rel="alternate" href="http://www.philcalcado.com/2011/10/08/on_the_testing_in_clojure_debate.html"/>
    <content type="html">&lt;p&gt;As said &lt;a href="http://philcalcado.com/2011/09/23/an_afterthought_leaving_thoughtworks.html"&gt;before, I recently moved from London to
Berlin&lt;/a&gt;. Last
week was my first time at the &lt;a href="http://www.meetup.com/Clojure-Berlin"&gt;Berlin Clojure User
Group&lt;/a&gt;, a very friendly and
interesting meetup.&lt;/p&gt;

&lt;p&gt;At some point, the conversation focused on testing in
Clojure. Recently, Rich Hickey said something at the Strange Loop
conference comparing Test-Driven Development to &lt;em&gt;driving a car
around banging into the guard rails&lt;/em&gt; --I actually don't know the exact
words, I wasn't there and didn't see any video. &lt;a href="http://blog.objectmentor.com/articles/2009/06/05/rich-hickey-on-testing"&gt;This is not the first time Rich says something like
this&lt;/a&gt;,
and years ago &lt;a href="http://www.informit.com/articles/article.aspx?p=1193856"&gt;Donald Knuth said something similar&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It should be very clear to readers of this blog that &lt;a href="http://www.google.de/search?q=site%3Aphilcalcado.com+%2B%22tdd+OR+test-driven%22"&gt;I use Test-Driven Development
in pretty much all code I
write&lt;/a&gt;;
but I have absolutely no problem with what Rich or Don said.&lt;/p&gt;

&lt;h2&gt;I have a limited view of the development world&lt;/h2&gt;

&lt;p&gt;Over the past decade I've been writing systems for banks, real-time
billing systems, massive scale multimedia distribution and all sort of
&lt;em&gt;application&lt;/em&gt; domains. I am convinced that this kind of work
benefits a lot from having executable specifications written up
front, and to me the best way to write executable specifications is
with tests. I was never paid to write a programming language or any
hardcore systems-level code, though&lt;/p&gt;

&lt;p&gt;Just as some hardcore systems programmers tend to say things that are
completely bogus in my world (in the old days this would be something
like &lt;em&gt;"real men write it in C"&lt;/em&gt;), I am  aware of the fact that
I shouldn't try to sell the tools I find useful in my tiny little
corner of the development world to everyone.&lt;/p&gt;

&lt;p&gt;I have friends who solve hard problems without even
running a test for months, and it works for them. Could their feedback
cycle be made shorter by introducing TDD cycles? I suspect yes, but I
have no experience in the kind of work they do; so instead of bringing
in my pitchfork and torch I would rather seat down with them over
beers and compare notes.&lt;/p&gt;

&lt;h2&gt;TDD is neither requirement, nor guarantee&lt;/h2&gt;

&lt;p&gt;One thing I've learned early in my career was to always read the source
code of whatever tool I am using. Since I started playing around with Clojure I tried to get
myself familiar with the implementation of the language, and &lt;a href="http://philcalcado.com/2009/02/01/clojure-adding-metadata-to-java-objects-and-proxies/"&gt;even
hacked around a bit whenever there was some need or
opportunity&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As someone who spent the past few years reading the Clojure code base
every now and then, I don't have a lot to complain about the
readability of the code.&lt;/p&gt;

&lt;p&gt;Interestingly, the same mindset of &lt;em&gt;always read the source
code&lt;/em&gt; made me read many frameworks, libraries and tools in
multiple languages. There is little correlation between readable
code and usage of TDD by the author; even though usage of TDD by the
developers makes me &lt;strong&gt;much more confident in changing code&lt;/strong&gt; and
sending a patch, even if the code is a mess.&lt;/p&gt;

&lt;p&gt;There is no real guarantee that a TDD code base will provide you with
better or more readable code; what TDD helps with in this case is
making it much easier to know if a change to some piece of --good or
bad-- code is correct or if you broke something by mistake.&lt;/p&gt;

&lt;h2&gt;So...?&lt;/h2&gt;

&lt;p&gt;So what's the deal, should we do TDD in Clojure or not? &lt;a href="http://philcalcado.com/2011/08/29/my_experience_with_test/driven_development_in_clojure_and_functional_programming.html"&gt;I surely
believe that most people would benefit from TDD in Clojure, Scala and
other Functional
languages&lt;/a&gt;;
it works for me, has been working for a decade. I am more than happy
to show you how so, and see if I can help you in applying the
techniques I use in your reality (in fact, I just proposed a &lt;a href="http://www.meetup.com/Clojure-Berlin/events/31778922/"&gt;&lt;em&gt;Better
Functional Design in Clojure through TDD&lt;/em&gt; talk for the next Berlin
Clojure meetup, you should
come along&lt;/a&gt;!), but
there's no way I would say that this is the only way to have a good
and reliable code base.&lt;/p&gt;

&lt;p&gt;That said, just as I see a lot of die-hard TDD people complaining
about Rich and Don's words, I see a lot of &lt;em&gt;cool kids&lt;/em&gt; using them to
ditch good practices in software development as something irrelevant
in Clojure. Well, the last time I saw this happening was a couple of
years ago, when the &lt;em&gt;Ruby on Rails cool kids&lt;/em&gt; decided that Ruby was so
&lt;em&gt;awesome&lt;/em&gt; that they could just drop whatever practices they thought
were not &lt;em&gt;cool&lt;/em&gt;. &lt;a href="http://avdi.org/devblog/2011/08/22/your-code-is-my-hell/"&gt;The consequences of this mindset are not, well,
awesome&lt;/a&gt;; so
be careful here.&lt;/p&gt;
</content>
    <summary type="html">I shouldn't try to sell the tools I find useful in my tiny little corner of the development world to everyone</summary>
  </entry>
</feed>
