添加快捷方法还是遵循 ActiveRecord 语义?
又是一次和朋友的争论。 考虑这段代码:
class User < ActiveRecord::Base
has_many :groups
def in_group?(group)
groups.include?(group)
end
end
class Group < ActiveRecord::Base
has_many :members
def add_user(user)
members << user
end
end
我的观点是,这些方法给代码增加了额外不必要的复杂性,并且很难猜测——就像为什么#in_group? 但不是#is_a_member_of?,或者为什么是#add_user 而不是#add_member,等等。 根据我 4 年的 Rails 经验和总共 20 年的编程经验,我最好遵循 AR 语义并使用 User#groups.include?(group) 和 Group#members << 用户。 它们很容易猜到,如果我需要一些额外的功能,我可以使用 has_many :members 的回调并覆盖 User#groups.include? 如果有必要的话,在关联扩展模块中。
然而我的朋友认为,最好使用快捷方式来创建“抽象点”,并且最好扩展此代码而不是使用回调或重载。
你怎么认为?
PS 需要明确的是,我讨厌“假设”方法:)
Yet another argument with a friend of mine. Consider this code:
class User < ActiveRecord::Base
has_many :groups
def in_group?(group)
groups.include?(group)
end
end
class Group < ActiveRecord::Base
has_many :members
def add_user(user)
members << user
end
end
My opinion is that these methods add extra unnecessary complexity to the code and are hardly guessable — like why #in_group? but not #is_a_member_of?, or why #add_user but not #add_member, and so on. Coming from my 4 years experience with Rails and total 20 yrs programming experience, I'd better follow AR semantics and use User#groups.include?(group) and Group#members << user. They are easily guessable and in case if I'll need some extra functionality, I can use callbacks for has_many :members and override User#groups.include? in the association extension module if that would be necessary.
However friend of mine argues that it is better to use shortcuts to creates "points of abstractions" and it is better to extend this code rather than using callbacks or overloads.
What do YOU think?
P.S. just to be clear, I hate "WHAT IF" approach :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我完全同意不应该添加这些方法。 创建其他相关对象不是模型的工作。 这就是协会代理的工作。 我还要注意重写关联代理行为,因为由于代理的实现方式,您可能会看到一些奇怪的副作用。
I totally agree that these methods should not be added. It's not the job of models to create other related objects. That's the job of the association proxy. I'd also beware of overriding association proxy behaviors, since you're liable to see some strange side effects due to the way the proxies are implemented.
您引用的样式在“德米特法则”下是合理的,该法则警告客户端代码不要直接操作
组
或成员
。The style you quoted is defensible under the "Law of Demeter", which cautions against client code manipulating
groups
ormembers
directly.我绝对赞成抽象,但不赞成这种执行。 您的朋友提出了一个很好的观点,如果您确定成员是否在群组中的方式要改变怎么办? 您有大量的重构工作要做,祝您好运!
然而,我看到了将令人困惑的函数放置在错误位置的论点。 我想说你的组织不正确,为什么不将它们附加到特定的关系模型对象呢?
示例:
或者
对我来说,这看起来更优雅,也更冗长,但是您的分离更相关。
I am definitely in favor of abstraction, but not in this execution. Your friend raises a good point, What if how you determine if a member is in a group is going to change? You've got a ton of refactoring to do, good luck with that!
However, I see the argument of placing confusing functions in the wrong places. I'd say you've got an incorrect organization, why not attach them to the specific relationship model object?
example:
or
That to me looks much more elegant, its a bit more verbose, but your separation is more relevant.
对于
in_group?
:您的方法名称可以从一个方向猜测 - 当您阅读它时,它的作用非常明显。 这是重要的可猜测类型。 当有人维护此代码时,他不会陷入in_group?
调用。 它还更具声明性和简洁性,从而提高了可读性(在这种情况下略有提高,但通常很好)。 这是一种 Smalltalky 方法。另一方面,我认为
add_user
方法是不必要的。 它看起来并没有特别简洁或直接,只是不标准。 这个名字仍然相当明显,并且没有太大的危害,但我看不出它有什么好处。 它看起来更像是一条风景优美的路线,而不是一条捷径。For
in_group?
: Your method name is guessable in one direction — it's pretty obvious what it does when you read it. This is the important kind of guessable. When somebody is maintaining this code, he won't get caught up on thein_group?
call. It's also more declarative and concise, which improves readability (marginally in this case, but it's good as a rule). It's a Smalltalky kind of method.On the other hand, I think the
add_user
method is unnecessary. It doesn't seem particularly more concise or direct, just nonstandard. The name is still fairly obvious and not egregiously harmful, but I don't see the benefit to it. It seems like more of a scenic route than a shortcut.当有原因时(例如成为团体中的“成员”会改变含义),我赞成这些方法。 这些方法封装了会随着时间的推移而增长和变化的逻辑,并且确实有助于测试。 这不是面向对象编程的全部意义吗?
I'm in favor of these methods when there is cause (such as being a "member" in a group changes meaning). Having these methods encapsulates logic that will grow and change over time, and does aid in testing. Isn't this the whole point of OO programming?