5

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

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 查找提要是异常的):

  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 方法并让它们在发生错误时抛出异常更好?

4

3 回答 3

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's 简洁地编写它maybe

def self.fetch(feed_id)
  Feed.find_by_id(feed_id).maybe.fetch
end

3) 抛出异常(因为不通过 id 查找提要是异常的):

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

于 2012-06-02T12:51:56.367 回答
2

我认为正确的答案是:视情况而定。从理论上讲,用户应该永远不会遇到来自框架的任何错误消息。您必须时刻准备好处理这些异常。选择权在你手中(如果它不是外部使用的接口或其他东西)。

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

第二种解决方案基本上是这样,但有一个内部处理。使用 nil 表示存在问题。它也必须被处理,报告给用户,或其他东西。缺点是如果忘记这一点,可能会误导用户。

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

于 2012-06-02T12:39:49.807 回答
2

我会选择干净的版本。

如果您不向该方法提供 a feed_id,则fetchruby​​ 本身将 raise ArgumentError: wrong number of arguments(0 for 1),因此#3 的第一部分毫无意义。

如果您不提供有效的feed_id,则Feed.find(feed_id)调用将引发不同的异常,很可能会ActiveRecord::RecordNotFound显示一条消息,说明它找不到具有所提供 ID 的提要,或者如果没有提供 ID(feed_id参数为nil),则它找不到没有 ID 的提要。

对我来说,用 调用该方法似乎有点愚蠢feed_id = nil,所以我可能会争辩说“如果你发送无效的输入,它可能会中断”,在这种情况下,我认为这ActiveRecord::RecordNotFound会给你更多关于哪里出了问题的信息比你提高一个ArgumentError.

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

于 2012-06-02T12:45:51.850 回答