使用动态类型语言进行重构

时间:2010-08-12 13:33:45

标签: ruby dynamic refactoring

好吧,我不是想在这里开始一场火焰战争,我知道静态语言和动态语言之间的争论已被多次化,包括这里。但我有一个非常实际的问题,希望这里有人可以提供一些启示。抱歉这个长度,但这不是一个简单的问题,可能不是一个简单的答案。

Ruby,PHP和Javascript现在是非常受欢迎的语言,他们有很多人为他们辩护,并认为动态输入并不能阻止开发人员回归。我是这些语言的新手,并希望开始将它们用于更大的项目,但这里是一个基本的重构场景,一直在工作(work == C#),我想知道这种方法是什么Ruby - 我之所以选择Ruby是因为它是OO。

好的,我正在使用Ruby,我构建了一个Customer对象。它具有从数据库加载/保存/删除的方法。很好,人们使用它。我为其他东西添加了更多方法,人们更多地使用它。我添加了一种基于某些参数计算订单历史的方法。到目前为止,这个类正在整个系统中使用。然后,有一天我决定更改GetOrderHistory方法的参数。所以我:

  • 将新参数添加到方法
  • 重写方法的代码以使用新参数
  • 更改我想到的客户端代码以传递新参数并使用此修改后的方法

但现在呢?我有几十个/几百个/谁知道系统中有多少其他需要更改的地方。在像Ruby或Javascript这样的动态OO语言中,我该怎么做呢?

脱离我的头脑,不太了解Ruby,我能想到两个愚蠢的答案:

  1. 100%代码覆盖率。我测试整个应用程序,每次打破我看看是否是那个方法并修复它
  2. 查找和替换。我使用文本搜索来查找该方法。但是我可以使用相同的方法名称来创建其他对象。
  3. 对此有一个很好的答案吗?看起来IDE会很难。如果我有像

    这样的代码
    c = Customer.new
    

    它能够弄明白,但如果它是

    c= SomeFunctionThatProbablyReturnsACustomerButMightReturnOtherThings()
    

    那么Ruby专家会采用什么方法处理这种情况?

2 个答案:

答案 0 :(得分:3)

你会听到的一个强有力的论据是你应该事先写下测试。理论上,这将显示应用程序需要更改的确切位置,以防其他内容发生变化。

但这只是冰山一角。 Ruby在设计时考虑了一些指导原则,如简短的表达功能,模块中的职责分离,不重复代码(DRY),最少惊喜的原则等;加上一组推荐的做法,比如先测试,将参数作为哈希选项传递,明智地使用元编程等等。我相信其他动态语言也可以这样做。

如果c不是客户,那么至少我希望行动就像一个人。 IDE可以查找duck typing,这比检查特定类的实例更灵活。

一些IDE(至少是Rubymine)也会查看约定。例如,在Rails应用程序中,Rubymine转到模式文件并将数据库属性作为方法添加到数据库中。它还识别关联(has_many,belongs_to等)并动态添加Rails生成的相应方法。

现在,这几乎减少了重构的需要,至少将其保持在最低限度。但肯定无法解决它。我不认为它可以解决。

答案 1 :(得分:1)

这可能不是你问题的最佳答案,但我倾向于设计方法来接受哈希以涵盖未来的变化。

示例:

def my_method(options = {})
  if options[:name]
    ...
  end
end

我认为很多更高级的Ruby人员都希望实现某种元编程模式。

其他选项可能包括在子类中覆盖该方法以执行您想要的功能。

或者,怎么样......

def get_order_history(required_param, options = [])

  @required_param = required_param

  if options[:do_something_else]
    result = other_method(options[:do_something_else])
  else
    result = ...
  end

  result      

end

def other_method(something_else)
  ...
end