Ruby流控制:抛出异常,返回nil或让它失败?

时间:2012-06-02 09:44:50

标签: ruby-on-rails ruby flow-control

我正在考虑流量控制的最佳实践。我应该走哪条路?

1)不要检查任何内容并让程序失败(更干净的代码,自然错误消息):

  def self.fetch(feed_id)
    feed = Feed.find(feed_id)
    feed.fetch
  end

2)通过返回nil默默地失败(但是,“清洁代码”说,你永远不应该返回null):

  def self.fetch(feed_id)
    return unless feed_id
    feed = Feed.find(feed_id)
    return unless feed
    feed.fetch
  end

3)抛出异常(因为特殊情况下不能通过id找到Feed):

  def self.fetch(feed_id)
    raise ArgumentError.new unless feed_id
    feed = Feed.find(feed_id)
    raise ArgumentError.new unless feed
    feed.fetch
  end

换句话说:我应该积极地使用保护条件,还是更好地依赖Ruby / Rails方法并让它们抛出异常,如果出现错误?

3 个答案:

答案 0 :(得分:6)

  

1)不要检查任何东西,让程序失败(更干净的代码,   自然错误消息):

使用已知的,记录的异常“让程序失败”是可以的,但是因为你试图使用NoMethodError对象而得到一个令人不快的nil只是粗心大意。在您的特定示例中,ActiveRecord#find会引发记录的ActiveRecord::RecordNotFound异常,因此IMO就是这样的:

def self.fetch(feed_id)
  Feed.find(feed_id).fetch
end
  

2)通过返回nil默默地失败(但是,“清洁代码”说,那   你永远不应该返回null):

这很好,作为一般建议,但Ruby充满了返回nil的方法;并且没关系(再次,只要它被记录),它只是意味着“没有”(并允许非常紧凑的模式something_that_can_be_nil || another_value)。在这种情况下,我会使用Ick的maybe

简明地写出来
def self.fetch(feed_id)
  Feed.find_by_id(feed_id).maybe.fetch
end
  

3)抛出异常(因为特殊情况下不能找到饲料   ID):

是的,但是让方法引发众所周知的RecordNotFound异常,而不是自定义异常(除非您想要抽象使用AR的事实,这可能非常麻烦)。

答案 1 :(得分:2)

我认为正确的答案是:它取决于。用户理论上应该永远不会遇到来自框架的任何错误消息。您必须始终准备好处理这些异常。选择是你的全部(如果它不是外部使用的界面或其他东西)。

如果您采取第一条路线,我认为您应该首先查询存在该ID的任何Feed,然后尝试获取它。如果Feed在两者之间消失,那么报告可能是一个真正的问题。第三个基本相同。您需要确保,您处理了所有情况,并且抛出异常可以帮助防止用户看到错误。

第二个解决方案基本上是这个,但内部处理。没有,你发出信号表明有问题。它也必须处理,报告给用户或其他什么。缺点是如果你忘记了这一点,你可能会误导用户。

我会使用第一种方法,之前需要额外检查以确保它存在。但这取决于使用情况。

答案 2 :(得分:2)

我会选择干净的版本。

如果您没有向feed_id方法提供fetch,则ruby本身会引发ArgumentError: wrong number of arguments(0 for 1),因此#3的第一部分毫无意义。

如果您没有提供有效的feed_id,那么Feed.find(feed_id)来电会引发另一个异常,很可能是ActiveRecord::RecordNotFound,并显示一条消息,说它无法找到Feed使用提供的ID,或者如果未提供ID(feed_id参数为nil),则无法找到没有ID的Feed。

对我而言,使用feed_id = nil调用方法似乎有点愚蠢,所以我可能会争辩说“如果发送无效输入,它可能会中断”,在这种情况下,我认为{{ 1}}会提供有关出错的更多信息,而不是提出ActiveRecord::RecordNotFound

返回空值很少是好事,因为这不会告诉你实际出了什么问题。因此,我也排除了#2。