前几天我正在寻找一个Ruby代码质量工具,我遇到了pelusa宝石,看起来很有趣。它检查的一件事是给定Ruby文件中使用的else语句的数量。
我的问题是,为什么这些不好?我理解if/else
语句经常会增加很多复杂性(我认为目标是降低代码复杂性)但是如何在没有else
的情况下编写检查两种情况的方法?
总结一下,我有两个问题:
1)除了降低代码复杂性之外还有其他原因可以避免使用其他语句吗?
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
- 更少的方式来写这个我没想到的吗?
我想我在这里寻找风格方面的考虑因素。
答案 0 :(得分: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
方法提供两种不同的行为。这样的代码违反了单一责任原则,因为你的方法做了不止一件事,这就是你应该首先编写两种方法的原因。
答案 1 :(得分:2)
def deliver_email_verification_instructions
subj = (Rails.env.test? || Rails.env.development?) ? self : delay
subj.deliver_email_verification_instructions!
end