Ensure With Explicit Return

Quick! What does the following method do when thing.method_that_might_raise! raises SomeAppException? And why is this a code smell?

1 def some_method
2   thing.method_that_might_raise!
3   ensure
4     return thing
5 end

Before giving the answers to these two questions, let’s go over what ensure does.

The ensure clause in Ruby is run regardless of whether a block has thrown an exception or not. A simple example is opening a file1:

 1 def file_open_with_auto_close(name, mode = 'w', &block)
 2   f = File.open(name, mode)
 3   puts "calling your block"
 4   yield f
 5   ensure
 6     if f
 7       f.close
 8       puts "file safely closed"
 9     end
10 end
11 
12 file_open_with_auto_close('test') do |file|
13   file << 'data'
14   raise 'exception raised'
15 end
16 #
17 #calling your block
18 #file safely closed
19 #RuntimeError: exception raised
20 #  from (irb):14
21 #  from (irb):4:in `file_open_with_auto_close'
22 #  from (irb):12

Even if there is an exception while processing the file, like the one we raise on line 14, ensure allows us to close the file.

After the ensure clause has run, Ruby either continues the exception handling (in this case irb rescues it and gives us a stack trace) or continues executing the block.

Except if you have an explicit return statement in your ensure clause.

Let’s take a look at the difference in irb, first without an explicit return statement:

 1 def ensure_without_return
 2   yield
 3   ensure
 4     puts 'ensure'
 5     true
 6 end
 7 
 8 ensure_without_return { puts 'block'; false }
 9 #
10 #block
11 #ensure
12 #=> false
13 #
14 ensure_without_return { raise 'exception raised'; puts 'block'; false }
15 #
16 #ensure
17 #RuntimeError: exception raised
18 #  from (irb):21
19 #  from (irb):16:in `ensure_without_return'
20 #  from (irb):21

Note that although the ensure clause is run after the block from line 8, it has not changed the return value of the method.

And now with an explicit return statement:

 1 def ensure_with_return
 2   yield
 3   ensure
 4     puts 'ensure'
 5     return true
 6 end
 7 
 8 ensure_with_return { puts 'block'; false }
 9 #
10 #block
11 #ensure
12 #=> true
13 #
14 ensure_with_return { raise 'exception raised'; puts 'block'; false }
15 #
16 #ensure
17 #=> true

The first thing to note is that the return of the method is now determined by the return statement in the ensure clause on line 5.

The second thing to note is that the explicit return statement acts as an implicit rescue clause, allowing the code to resume as if no exception had been raised.

Summarizing:

  • an ensure clause runs whether an exception is raised or not
  • an ensure clause without an explicit return statement does not alter the return value
  • using the explicit return changes the control flow as if a rescue Exception clause was in place before the ensure clause

Back to our original questions. You should now know what the method does when thing.method_that_might_raise! raises SomeAppException.

But why is this a code smell? Consider the following code:

1 def some_method
2   thing.method_that_might_raise!
3   rescue Exception
4     # we have rescued all possible exceptions
5   ensure
6     return thing
7 end

Line 3 is a code smell. Rescuing all exceptions is not desirable. From our exploration of ensure we can see that this code is the equivalent of the original code.

Can we refactor it? Yes. Yes we can.

When we can recover from SomeAppException, we can just rescue:

1 def some_method
2   begin
3     thing.method_that_might_raise!
4   rescue SomeAppException => e
5     # do something clever here
6   end
7   thing
8 end

And when we cannot recover from SomeAppException, we just let the exception propagate up the call stack:

1 def some_method
2   thing.method_that_might_raise!
3   thing
4 end

1 File.open already does this.

Pairing With Hitch

Pair programming does present some unique problems, one that we encountered at Hashrocket was commit attribution: a commit message would be identified with one member of the pair only. This is not exactly tragic, but from the perspective of a passioniate developer, having commit credit (and accountability) is a critical and visible part of the ethos.

Tim Pope had the brilliant idea of using a group email address with tags (such as group+you@example.com) to identify the commits a pair made to git. A little bash script fu lead to a nifty command line utility that let us track pairs with our git commits. With that script as a starting point, Ro Samour wrote a pure ruby implementation: hitch

hitch will modify your git configuration to reflect who you are pairing with. Here is a hitch commit message using git log --pretty=full:

commit e518dd0637e7d1d77d3bd79a645e5d0bc93eae2d
Author: Les Hill and Rogelio Samour <bleep+bleep+bleep@hashrocket.com>
Commit: Les Hill and Rogelio Samour <bleep+bleep+bleep@hashrocket.com>
 
    Adding show note icon

This is a commit message from hitch on github:

Github hitch commit message

hitch is open source and is available from github.

Getting started

You will need to install the hitch gem from github1:

% sudo gem install therubymug-hitch

You will need a group email account with a service such as GMail that allows email tags2 (as an example, news is a tag in this email address yourname+news@example.com which is considered to be the same email address as yourname@example.com):

You really want a Gravatar for your group email account so that the commits show the custom gravatar along with your commit messages. For every pair, register a new gravatar and associate it with a tagged email address of the form:

dev+github_user_1+github_user_2@example.com

The github usernames should appear in the local part of the address in alphabetical order after the group address local part, each github username seperated by a +.

Initialize hitch by running hitchrc and giving it your name, github username, and group email address when prompted:

% hitchrc

Using hitch

To pair with another developer whose github username is pair:

% hitch pair

hitch will prompt you if it does not recognize github username of your pair and save it for later use.

To unpair and code solo:

% unhitch

To see who you are currently paired with:

% hitch

1 Add github.com to your gem sources with gem sources -a http://gems.github.com/

2 Read about email tags on Wikipedia

Most Bugs Fall to the Second Pair of Eyes

While recently discussing if a power law applies to bugs at the ongoing seminar I sentimentally call work, I noted a corollary to Linus’s Law.

Linus’s Law states:

Given enough eyeballs, all bugs are shallow

The corollary is:

Most bugs fall to the second pair of eyes

That is, just having one other developer look at a bug will likely resolve it. Of course, developer’s who are pair programming already know this and are ahead of the game.

On a related note, pretty much every developer has been in the following situation. You are called over by a collegue to look over a bug, often accompanied by the statement, ‘This should work.’ You give a cursory examination and you resolve the problem with a quick change, often one that is obvious (after you pointed it out!)

If you come away from that experience thinking ‘Fresh pair of eyes’ or some such, good for you, you passed the test.

If you come away from that experience thinking ‘I am so awesome!’ or some such, not so good for you, you are probably not even competent.

Velocity Is Not Destiny

One of the most persistent and pernicious stumbling blocks I see when a team is starting out with Agile1 is equating story points and velocity directly with hours.

Often this stumbling block is not apparent immediately; it often crops up after a few iterations have passed. As an example, a stakeholder who was new and unsure about agile, was eager to have a release a month into development as an affirmation of the decision to go with an agile approach. After we had prioritized the feature set for the release, he turned to me and said, “Let’s see, we have 78 points in the release, so we can deliver the release four weeks from today.”

My answer, “Not exactly”, surprised him.

If the velocity of the team is an evidence-based number using the teams own story point estimations, how could such a statement be incorrect? There are two related reasons such a statement needs to be qualified to be useful, the Planning Fallacy and Velocity is not Destiny2.

The Planning Fallacy

As described in the Overcoming Bias blog, when students were asked in an experiment to forecast when they would complete an assignment:

“Even when asked to make a highly conservative forecast, a prediction that they felt virtually certain that they would fulfill, students’ confidence in their time estimates far exceeded their accomplishments.”
More generally, this phenomenon is known as the “planning fallacy”. The planning fallacy is that people think they can plan, ha ha.

Since giving up on planning is not an option, we can make our estimates better through various techniques, one of which is to plan based on similarity to other known efforts, instead of estimations of time.

a cross-cultural study, found that Japanese students expected to finish their essays 10 days before deadline. They actually finished 1 day before deadline. Asked when they had previously completed similar tasks, they responded, “1 day before deadline.”

Agile mitigates the planning fallacy by eschewing estimates in hours or days and using story points3. Story points are abstract esitmations based on similarity; a 4 point story should be of the same relative size or complexity as any other 4 point story. Time is not a factor with story points.

Velocity is not Destiny

Given that story points yield better estimates, and velocity is an evidence based aggregate number smoothing out variations in individual stories, why qualify saying we can deliver four weeks from today? Velocity is a continuous measurement of the past performance of your team and is not a constant. The velocity of your team is a dynamic variable giving you direct and constant insight into how they are progressing. A future iteration has no velocity, as it has not been (and cannot yet be) measured. We can make predictions about future iterations based on velocity, but we cannot make any iron-clad guarantees.

An analogy might help explain how to think of velocity. You are taking a long automobile trip you have never taken before, where you will leave at 9 a.m. and travel 250 miles to arrive at your destination. Your car will accurately report your average velocity on the trip. 125 miles into the trip, your car reports an average velocity of 62.5 miles per hour, and you are currently on the highway going 70 miles per hour. How long do you have left, and how much money would you bet that you are accurate within one minute? Intuitively, most people understand that although the very clear math says you are 2 hours away from your destination, there are too many pitfalls such as traffic, accidents, road work, weather conditions, signals, etc to make a prediction that is accurate to the minute. (With your final average velocity, the very clear math will yield an exact and accurate result.)

Making the Release

There are many pitfalls in any software project, the one which was making me cautious about our release was a common one for novice stakeholders, Release Induced Focus. RIF is the tendancy for novice stakeholders to only really pay attention when they have an immediate release pending, leading to a spike in the number of stories rejected and bugs filed, and a corresponding drop in velocity. Given an experienced stakeholder who is rigorous about acceptance, the bug tax on velocity is taken out of velocity over time; with RIF the entire bug tax on velocity is paid in one or two velocity sapping iterations.

After explaining this, and using velocity as a predictor, we adjusted our plan for the release. We reprioritized the backlog to front load all the required features, moved unneeded features out of the release, and had the stakeholders exercise more rigor when doing their acceptance. The release was made in four weeks, with the team and stakeholders delivering tangible value without the long hours and anxiety provoked by more static approaches to software project management.

Velocity is a Dynamic Measure

Velocity is a continous measurement of your team’s past performance over time; all of the previously known and unknown risk variables have been surfaced, made known, become constants, and reduced to one accurate numeric measure. What velocity does not tell you is what the future holds. To quote every mutual fund prospectus ever written:

Past Performance is no Guarantee of Future Results

Understanding that velocity is accurate and dynamic is key to using it for iteration planning. Most other software project management methodologies pretend that the project is static in all aspects, that all variables are known and quantified. Agile acknowledges that a software project is a dynamic system, and provides simple evidence based tools to manage the dynamism inherent in building new software.

1 I use the term to encompass the variations of Agile methodologies that use story points and velocity.

2 I first heard this poetic phrase from Amy Kline, an awesome scrum master and friend.

3 Peter Jackson has written a great summary of why we use story points in The Case for Story Points .