The right tool for the job

James Iry recently wrote a post about type systems in which he ranked type systems according to two characteristics, safety and sophistication. We had an interesting discussion about it on IRC afterwards, in which one of the things discussed was whether these were really the right axes.

It occurred to me that we spend a lot of time talking about the major axes on which you compare programming languages, and that it would be interesting to gather some data on what these actually were instead of just plucking things that seem like they may sense out of the air. So I’ve created a little app to gather data for this: Check out The Right Tool, and I’d love it if you’d rank some languages on it.

Essentially the idea is this: I have a list of statements and a list of programming languages, and I want you to rank those languages in order of how well the statements apply to them.

At the moment I’m just data gathering: I don’t actually do anything with the data. The end goal is that I’m going to have a very high dimensional representation of each programming language in terms of what people think of them and why they use them which I will do some sort of dimension reduction to, hopefully giving rise to some interesting metrics with which to compare languages.

A couple notes:

  • This is not about which language is best. It’s about comparing the strengths and weaknesses of different languages
  • I’m not making the data available yet, but I promise I will later once I’ve gathered enough
  • The site looks like ass. I know. I’m not a web designer. Deal with it or send me a better stylesheet
  • If I’ve missed any languages out, let me know. Drop me a comment or something. Similarly if you have ideas for good statements you haven’t seen on the site
This entry was posted in Data geeking, programming on by .

The best way to handle exceptions

So, it’s well known that you shouldn’t have code that looks like this (examples in ruby and ruby-like pseudo code, but they’re trivially translatable to any other language):

begin
   do stuff
rescue
end

i.e. you’re swallowing the exceptions because they scared you and you wanted to hide them. This is naughty.

A more subtle trap people fall into is the following example from the rails boot.rb (this isn’t a rails specific problem. I see it everywhere)

    def load_rails_gem
      if version = self.class.gem_version
        gem 'rails', version
      else
        gem 'rails'
      end 
    rescue Gem::LoadError => load_error
      $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION
      exit 1
    end 

Let’s consider the results of this rescue block: A generic error message is printed, and we exit with a non-zero status code.

Now let’s consider the results of not having this rescue block: A specific error message is printed, we exit with a non-zero status code and we get a stack trace telling us exactly what went wrong.

So by including this rescue, we have lost information. Often this information doesn’t matter, but as it turns out in this case it does: If you have a gem version clash where rails depends on a different version of a gem that has already been loaded you will get a Gem::LoadError and, consequently, a very misleading error message.

I don’t want to pick on rails. Well, correction. I don’t want to pick on rails here. This post is actually inspired by a similar incident at work: There was a piece of code that basically looked like this:

begin
  connect to server
rescue
  STDERR.puts "Could not connect to server"
  exit
end

And were getting very puzzling errors where we were sure all the details were correct but it was failing to connect to the server. Once we deleted the rescue code it was immediately obvious why it was failing (if you care, the reason was that we weren’t loading the config correctly so it was trying to connect with some incorrect default values).

Which brings me to the point of this article: The best way to handle exceptions is not to handle them. If it’s not an exception you can reasonably recover from, the chances are pretty good that the default behaviour is more informative than the “helpful” code you were going to write in order to catch and log the error. So by not writing it you get to have less code and spend less time debugging it when it inevitably goes wrong.

This entry was posted in Uncategorized on by .

DataMapper: A (partial) retraction

Ok, so the DataMapper guys left a comment on my post, and I’ve talked to them on IRC. They were remarkably pleasant about it. It turns out that in DataMapper 1.0 there will be functionality to make saves throw exception on failure. It’s off by default, but you can turn it on globally, on a per class level, or on a per instance level.

While I still think the default behaviour is inherently broken, being able to unbreak it with a single line is definitely good enough for me and I can understand not wanting to make quite such a huge breaking API change.

So, well done to the DataMapper guys.

This entry was posted in programming on by .

DataMapper is inherently broken

This contains overtones of a post I’ve been resisting writing for months in the knowledge that the people who already agree with it will find it obvious while the people who don’t will bitch and moan and tell me that I’m stupid and perpetuate the same tired contentless arguments they always use.

So, having explained why this post is useless, I now add the caveat that I am writing it anyway, for the very simple reason that I am so angry at being proven right on the subject time and time again, and in particular at having had an entire morning wasted by this fuckwittery, that I am overriding my internal censor.

DataMapper is a ruby ORM library. It is inherently broken. Why? Because it considers booleans to be a superior solution to exceptions. This means that there is essentially no way to save data without falling into subtle and pernicious traps.

In DataMapper when you save an object, it returns false if it fails to save. You then need to ask it why it failed to save if, for some bizarre reason, you feel the need to care about little things like your data not making it into the database.

So, the code you end up writing all over the place looks like the following:

   my_account = Account.new(:name => "Jose")
   if my_account.save
     # my_account is valid and has been saved
   else
     my_account.errors.each do |e|
       puts e
     end
   end

Before anyone claims this is a contrived and silly example, here’s the source of it.

What’s the problem here?

Well… earlier I was called to help some colleagues. They were seeing really weird behaviour where save was failing but errors was empty. I was sure this must be a bug somewhere – it shouldn’t be possible. We even checked before the safe and valid? was returning true.

Which reminds me, another and sometimes recommended way of writing the above is to instead do…

   my_account = Account.new(:name => "Jose")
   if my_account.valid?
     my_account.save
     # my_account is valid and has been saved
   else
     my_account.errors.each do |e|
       puts e
     end
   end

Warning: If you do this, you are screwed. Your code is broken, even if it happens to work right now, and you will be bitten by it. Change it.

So, why is this code wrong?

Because the errors do not necessarily live on the object you are trying to save.

Suppose I instead had:

my_account = Account.new(:customer => Customer.new(:name => "jose"))

and tried to save this.

Well, it might fail to save, but return no errors.

Why? Because, it first has to save the customer. And that might fail to save. And if it does you won’t see any errors on the object you’re saving and have to hunt around to figure out what’s going wrong.

So, as well as having to explicitly check for errors on everything you attempt to save in order for your code to be correct, you must also explicitly check for errors on anything IT might helpfully decide to save for you.

This is untenable.

Code which fails should fail noisily. I shouldn’t have to work to find out why it went wrong, it should TELL me. If DataMapper did the obvious thing and threw an exception when something failed to validate then it would cut out a great deal of work and debugging effort, it would mean that I could simply handle the creation of a bunch of data and deal with the errors in one place instead of having to check everything for failures. It would mean that one could write code without living in a constant state of paranoia that you might make a mistake and forget to check a return code somewhere and then waste hours debugging when it finally bites you. And it would mean that not all the examples in their documentation would be wrong.

This entry was posted in Uncategorized on by .

Roasted Gnocchi with Butternut Squash and Cashews

Actually, the title of this dish basically sums it up, but it sure is tasty. Here’s how to make it:

Cube a small butternut squash. Toss it in olive oil and coarse salt. Roast for 10 minutes, then add an equivalent volume of gnocchi and toss it all together. Roast another 10 minutes. Add and toss about a third as much broken raw cashew nuts as you used squash/gnocchi and a dash of balsamic vinegar, roast 10 minutes more.

It’s really exceptionally tasty. I had a large first helping and then completely gratuitous seconds.

I’d meant to add rosemary, but forgot. It doesn’t really need it, but it would definitely have been an improvement.

This entry was posted in Food on by .