7

前几天我在寻找一个 Ruby 代码质量工具,偶然发现了pelusa gem,它看起来很有趣。它检查的一件事是给定 Ruby 文件中使用的 else 语句的数量。

我的问题是,为什么这些不好?我知道if/else语句通常会增加很多复杂性(我知道目标是降低代码复杂性),但是如果没有else?

回顾一下,我有两个问题:

1) 除了降低代码复杂性之外,还有其他原因可以避免 else 语句吗?

2) 这是我正在开发的应用程序中使用else语句的示例方法。没有人你会怎么写这个?我能想到的唯一选择是三元语句,但这里有足够的逻辑,我认为三元语句实际上会更复杂,更难阅读。

def deliver_email_verification_instructions
  if Rails.env.test? || Rails.env.development?
    deliver_email_verification_instructions!
  else
    delay.deliver_email_verification_instructions!
  end
end

如果您使用三元运算符编写此代码,它将是:

def deliver_email_verification_instructions
  (Rails.env.test? || Rails.env.development?) ? deliver_email_verification_instructions! : delay.deliver_email_verification_instructions!
end

是对的吗?如果是这样,那不是更难阅读吗?声明没有else帮助打破这一点吗?有没有另一种更好的、else更少的方式来写这个我没有想到的?

我想我在这里寻找风格方面的考虑。

4

2 回答 2

6

首先让我说你的代码并没有什么问题,通常你应该知道,无论代码质量工具告诉你什么,都可能是完全无稽之谈,因为它缺乏评估你实际在做什么的上下文。

但回到代码。如果有一个类只有一个方法,其中代码片段

if Rails.env.test? || Rails.env.development?
    # Do stuff
else
    # Do other stuff
end

发生了,那完全没问题(对于给定的事情总是有不同的方法,但你不必担心这一点,即使程序员会因为你不与他们争论而讨厌你:D)。

现在是棘手的部分。人们非常懒惰,因此像上面这样的代码片段很容易成为复制/粘贴编码的目标(这就是为什么人们会争辩说应该首先避免它们,因为如果你稍后扩展一个类,你更有可能只是复制和粘贴东西而不是实际重构它)。

让我们以您的代码片段为例。我基本上提出了与@Mik_Die 相同的建议,但是他的示例同样容易被复制/粘贴为您的示例。因此,应该做的(IMO)是这样的:

class Foo
  def initialize
    @target = (Rails.env.test? || Rails.env.development?) ? self : delay
  end

  def deliver_email_verification_instructions
    @target.deliver_email_verification_instructions!
  end
end

这可能不适用于您的应用程序,但我希望您明白这一点,即:不要重复自己。曾经。每次你重复自己时,不仅会降低代码的可维护性,而且还会因此在未来更容易出错,因为你复制和粘贴的任何内容都可能发生一次甚至 99/100 次更改,但是剩下的一个事件是导致@disasterOfEpicProportions最终的原因:)


我忘记的另一点是@RayToal 提出的(谢谢:),即 if/else 构造通常与布尔输入参数结合使用,从而产生了诸如此类的构造(我有一个项目的实际代码)维持):

class String
  def uc(only_first=false)
    if only_first
      capitalize
    else
      upcase
    end
  end
end

让我们忽略这里明显的方法命名和猴子补丁问题,并专注于 if/else 构造,它用于uc根据参数赋予方法两种不同的行为only_first。这样的代码违反了单一职责原则,因为你的方法做的不止一件事,这就是为什么你应该首先编写两个方法。

于 2012-12-19T00:17:15.247 回答
2
def deliver_email_verification_instructions
  subj = (Rails.env.test? || Rails.env.development?) ? self : delay
  subj.deliver_email_verification_instructions!
end
于 2012-12-18T18:43:20.270 回答