toolmantim

Breaking hearts

May 14, 2007 17:45 (Sydney Australia)

Apparently Giles was so broken hearted about my 7 seven line snippet he felt the need to write a 1700 word entertainment piece blog post. I don’t mind a good hearty discussion on the lack of computer-science in the web programming field, but let’s get the facts straight.

1. lower(email) runs a full table scan as opposed to using the index. That’s bad programming in any language.

That’s true, for some cases, but if you’re using PostgreSQL—which we are—you can quite easily add an index on the lower() expression.

I didn’t think it needed to be said, but when you see an abbreviated snippet of AR code it’s probably best not to assume too much about the DBMS’s execution plan without knowing a bit more info.

2. What happens when you call it with: find_by_email("john@example.com", :conditions=>"true")

Nothing you wouldn’t have expected:


User.find_by_email('john@example.com', :conditions => 'true')
# User Load (0.000970)   SELECT * FROM users WHERE (lower(email) = lower('john@example.com')) AND (true) LIMIT 1
3. with_scope is a Rails technique. A Ruby developer, someone who learned the language, not just the framework, would write: find(:first, { :conditions=>"..." }.merge(options) Shorter, simpler and a transferrable skill you can use outside of ActiveRecord.

Unfortunately Hash#merge won’t help you here. Observe:

{:conditions => "lower(email) = lower('john@example.com')"}.merge({:conditions => "true"})
# => { :conditions => "true" }
# whereas I wanted:
#    { :conditions => "lower(email) = lower('john@example.com') AND true" }

with_scope gives you this desired behaviour.

For the record, I too agree that with_scope should be a protected method, and that using with_scope outside of AR is most probably naughty; but, using it internally, from within a well-tested ActiveRecord::Base subclass method, I think is just fine.

If you still feel that using with_scope internally is no better than sending polar bears to the slaughterhouse, do feel free to implement and publish your own version…

—tim: the idiot, self-saboteur, framework coder.

Comments

Lourens Naude


class Booking < ActiveRecord::Base
   class << self  
      def find(*args)
        if args.first.to_s.length == 10
           booking = find_by_reference(args.first)
           booking.nil? ? (raise ActiveRecord::RecordNotFound) : booking
         else
           super
        end
     end  
   end
end

I use the above technique from time to time.Most likely as vulnerable to being massacred as the one in your post ( we tumble to share, don’t we? ), but it works, for me, on my project, today.

Change is good, constraints can be broken but a helluva lot of individuals in the community get off on mud slinging and quite frankly, Gile’s post is out of scope (pun intended).

Tim Lucas

Lourens: thanks for sharing, and welcome to “overriding finders anonymous” :)

Here’s another version too:

class Booking < ActiveRecord::Base
  module StringExtensions
    def is_a_book_reference?(s)
      s.length == 10
    end
  end
  String.send(:include, StringExtensions)

  class << self  
    def find(*args)
      if (reference = args.first.to_s).is_a_book_reference?
        find_by_reference(reference) || (raise ActiveRecord::RecordNotFound)
       else
        super
      end
    end
  end
end

Gabe da Silveira

I read Giles post and was not very impressed with gandiose statements like “the code is actually very troubled” and “*opts is a bug, lacking an understanding of how Ruby handles arguments.”

To call the use of *opts here a bug belies the true intention of the author, which is to find any minor flaw and blow it out of proportion to make himself feel smart. Here’s a hint: good programmers get things done, they don’t obsess over the efficiency of every syntactic detail.

This is to say nothing of the ad nauseam jaw flapping that characterizes rest of the post. If Giles had simply written a short paragraph about how inefficient the base query was, that would have been an interesting critique with some justification (albeit wrong in your case), but instead he conflates some perceived flaws in your code with some greater Rails competency crisis.

In one breath he is proclaiming some minimum standard of competence, then several paragraphs later he explains the process of transforming a database column into lowercase values. If he wanted to write something useful, he could propose an actual solution to case-insensitive search or merging multiple conditions “the right way” instead of pretending there’s no actual problem here other than the hideous offense of your ill-conceived code.

Tabloid journalism.

giles bowkett

Tim, everything you quote me as saying here was contributed by somebody else, and I identified it as such in the post. And most of the post had nothing to do with you at all. And I apologized for the criticism at the end of the post. And the part about Hash.merge() not working, I pointed that out myself in the original post!

That bit about the :conditions=>true criticism being flat-out wrong, you got me there, I should have tested it instead of listening to the person who said it, but other than that, all I can do is say that the criticisms came from someone else – which I said in the original post – that I’m sorry to criticize – which I said in the original post – and that I know about the Hash.merge() thing, and I can prove it, because I said it in the original post.

As for the “tabloid journalism” guy, dude, get a life. If it’s so bad, what did you read it for? What possible responsibility could I have for the fact that you won’t stop reading something after you decide you don’t like it? If you don’t like it, don’t read it! That’s easy!

Anyway, I’m really sorry I got everyone so riled up. I read your blog because I think you’re a good programmer. I can’t complain about the criticism because I started it, but enough already. I’m sorry. My bad.

Assaf

That’s what happens when good intentions and high emotions run together :-) Sorry about that.

1. You can make a lot of assumptions about lower() that are true in some cases and not in others. But Giles’ retracted post, to which I replied, didn’t state any of these. I think it was a bad idea for his to repost that.

2. Now that I’m looking at what you were trying to accomplish, my mistake. I stand correct. You’re actually doing the right thing.

3. There was a longer exchange going on - thankfully not reposted, because at some point even I lost track trying to follow it - about the feasibility of extending where clauses in Rails. Suffice to say, I think the Rail’s limits are justifiable, but again it needs to have a context to make sense.

The point of my post is a disagreement with the role Rails plays in all of these. Like Giles I’m cynical enough to see the impending migration of framework coders to Rails. Giles talks about “the Rails culture”, which sounds like trying to see Rails fail before it even gets a chance. I happen to think it’s a great framework for enabling developers to deliver better code (e.g. it exposes the SQL better than most other frameworks, makes the right choices about URLs, is HTML centric, etc), but it’s also just another framework when it comes to framework coders. And no framework can prevent you from making mistakes. Rails is neither the problem nor the solution.

At least, that’s my thesis.

Gabe da Silveira

As for the “tabloid journalism” guy, dude, get a life. If it’s so bad, what did you read it for?

Look, I’m sorry if I offended you, but that’s a copout. I’m not saying your writing is bad, it was an engaging read. I read through to the end to give you a fair chance to make a convincing argument. At the end it all seemed to boil down to a vicious attack on a piece of code that’s not all that bad to begin with. Your mistake was to hold this up as some sort of paragon of wrong-thinking. In doing so you open yourself up to a lot of criticism and you ought to be able to take it.

Daniel

Oh! Haha!

”... good programmers get things done, they don’t obsess over the efficiency of every syntactic detail.”

Was there something said about the “lack of computer-science in the web programming” somewhere? Sorry, no personal offense, I just couldn’t resist.

Alex Fetcher

Great site!
49753de578e6f638101fad07e28165a5

To comment on this article you must have javascript enabled.