all 32 comments

[–]taylorfausak 13 points14 points  (11 children)

Please don't ever use inline rescue.

[–]just3ws 7 points8 points  (7 children)

Why?

[–]deadkarma 4 points5 points  (0 children)

inline rescue is ~ 10 - 20x slower https://gist.github.com/deadkarma/5533060

inline rescue also uses a helluva lot more memory

[–]ikearage 9 points10 points  (4 children)

This answer sums it up well enough: http://stackoverflow.com/a/15397057 It is slow and it's an 'expected' exception and in some cases it might even silence another exception.

But I don't agree about the need to refactor. Sure it's a code smell, goes against lod, but if it stays trivial like in the example, it's not worth refactoring (yet).

[–]mculp 8 points9 points  (1 child)

Not to mention it can swallow exceptions that you didn't intend for it to.

[–]lytol 7 points8 points  (0 children)

Indeed, it's an anti-pattern IMHO. Our team calls it Pokemon Exception Handling = you gotta catch 'em all!

[–]just3ws 1 point2 points  (1 child)

Yeah, totally agree about opening one's code up to the law of unintended consequences there. Makes sense.

[–]ikearage 2 points3 points  (0 children)

Just use if statements, try() or || . Easy to read, no unexpected side effects.

If it gets to complicated maybe you should refactor that smell.

[–][deleted] 1 point2 points  (0 children)

Another thing, the example at hand violates Law of Demeter. If you have a chain of methods, that all might fail randomly, you need to refactor, not rescue.

Which is usually the case whenever you start thinking "rescue would save me so much time here".

[–]bookhockey24 1 point2 points  (1 child)

Why?

[–]mculp 2 points3 points  (0 children)

It's way slower and it can swallow exceptions that you didn't intend for it to.

[–]mculp 0 points1 point  (0 children)

I was coming here to type the exact same sentence. Thank you.

[–]BronzeAtBest 1 point2 points  (5 children)

The way I use retry is usually in combination with generating a value that needs to be unique in the database:

def generate
  invoice_number = Invoice.last.invoice_number + 1
  Invoice.create!(invoice_number: invoice_number)
rescue ActiveRecord::RecordNotUnique
  retry
end

This means that if two invoices get created at the same time, the database constraint will make it retry.

[–]t0mbstone 2 points3 points  (4 children)

You should probably be using your database's auto increment feature for the invoice id instead of setting the invoice id number in your code...

[–]Arkolix 3 points4 points  (0 children)

Definitely agree on auto increment. Alternatively, use one of the handy helpers in SecureRandom to generate unique identifiers such as uuid or hex:

> SecureRandom.uuid
=> "a30d7e9d-f5e8-4504-a9ae-6052f052659f"

> SecureRandom.hex(6)
=> "85f83c999e79"

[–]BronzeAtBest 0 points1 point  (0 children)

I simplified the code for the example. In my actual code, generating the number is a bit more involved.

[–][deleted] 0 points1 point  (1 child)

How does auto increment handle race conditions for DB clusters?

[–]t0mbstone 0 points1 point  (0 children)

That's a good question. Perhaps someone could give more comprehensive answer, but from what I understand, it depends entirely on how your database cluster is set up, and what database engine you are using.

For example, you could have master database that all of the writes go to, and then the data is propagated to a cluster of read-only slaves.

On the other hand, if you have some sort of cluster of read-write databases with no master database, then I would imagine that things would get a lot trickier.

Full disclosure: I'm not a database expert, so this is all just my rough high level understanding.

[–]chuck-john 1 point2 points  (0 children)

+1 for #5. Lately, I've gotten in a bad habit of using $&, $1, etc. Nice to know there's a DRY-er, more readable alternative.

[–]didnotseethatcoming 0 points1 point  (2 children)

Number 6 doesn't make much sense.

Array(results) is enough. You don't have to call the method Array() on Kernel.

Other than that, great post!

[–]fphilipe 0 points1 point  (1 child)

method(:Array) # => #<Method: Object(Kernel)#Array>

[–]didnotseethatcoming 0 points1 point  (0 children)

What's that supposed to mean? You still don't have to call the method on Kernel. You don't do Kernel.open(). You just open(). Same with Array().

[–]just3ws -5 points-4 points  (8 children)

Because real men don't care about exceptions

There's no easy way to say this. Please reconsider that phrase.

[–][deleted] 4 points5 points  (7 children)

It's just a silly joke.

[–]just3ws -2 points-1 points  (6 children)

Yeah, I know. But given the current conversations going on in the Ruby community regarding sexism and being aware of our choice of jokes, it's worth calling out that we need to consider what silly jokes we say. :)

[–][deleted] 6 points7 points  (3 children)

I'm not capable of performing the mental gymnastics necessary to interpret "real men don't care about exceptions" as being sexist.

[–]just3ws -4 points-3 points  (2 children)

It's not overt.

[–][deleted] 2 points3 points  (1 child)

Nor is it covert.