【发布时间】:2012-05-23 15:10:46
【问题描述】:
我有一个正在使用 ruby 进行的项目,它需要一些工人的大量工作。大多数业务逻辑都包含在这些工作人员中,它们变得相当复杂。我设计的技术模拟了 compose 方法模式,但它严重依赖实例变量来保持状态。我设置它的方式似乎合乎逻辑,但我想从社区获得一些反馈,看看这是否有误,或者不是我可以设置的最干净的方式。
我基本上是在使用 worker perform (Sidekiq) 方法作为一种开关
def perform(transaction_id, data, account_id)
@transaction_id = transaction_id
@data = data
@account = Account.new(account_id)
@campaign_tag = nil
@match_str = nil
@options = nil
has_starter_tag || return
find_campaign || return
determine_options || return
find_active_option || return
reservation_over || return
already_filled || return
send_to_inventory
end
每种方法都遵循相同的逻辑。检查规则,如果不满意,执行操作(发送电子邮件等)并返回 false,从而停止执行。如果满意,则存储一些完成事务所需的 ivar 数据并返回 true,从而进入下一步。
def has_starter_tag
result = true
@campaign_tag = find_starter_tag(@account, @data[:variable])
if !@campaign_tag
result = false
send_email_about_badness
log_some_stuff
end
result
end
为了测试这段代码,我对每个方法所依赖的实例变量进行了存根。我知道这是一种代码味道,因为我的测试知道实现而不是接口。也就是说,我喜欢这些方法的干净界面,我觉得我可以扫描源代码并确切地知道发生了什么。
如果我做错了,有人可以花点时间解释一下正确的方法(或至少另一种方法)吗?我一直无法弄清楚如何处理那些必须执行许多似乎相互依赖的小步骤的对象。
【问题讨论】:
-
如何使用在工作线程中设置的前三个实例变量?
@campaign、match_str和options是用来做什么的?首先,我会让has_starter_tag和其他方法接受它们每个人都需要的参数。这将让您测试分离,而不是依赖于实例变量。 -
我更新了示例方法,以便更好地说明如何使用它。前 3 个变量本质上是大多数方法用于数据的常量。我可能应该指定这一点,但我在从
has_starter_tag外部方法中调用的方法中完成大部分工作。这些不访问实例变量,并且是单独进行单元测试的。