我最近看了RailsConf 2014的“ All Little Little”。在这次演讲中,Sandi Metz重构了一个包含大型嵌套if语句的函数:
def tick
if @name != 'Aged Brie' && @name != 'Backstage passes to a TAFKAL80ETC concert'
if @quality > 0
if @name != 'Sulfuras, Hand of Ragnaros'
@quality -= 1
end
end
else
...
end
...
end
第一步是将函数分解为几个较小的函数:
def tick
case name
when 'Aged Brie'
return brie_tick
...
end
end
def brie_tick
@days_remaining -= 1
return if quality >= 50
@quality += 1
@quality += 1 if @days_remaining <= 0
end
我发现有趣的是这些较小的函数的编写方式。brie_tick
例如,并不是通过提取原始tick
功能的相关部分来编写的,而是通过参考test_brie_*
单元测试从头开始的。一旦所有这些单元测试都通过,brie_tick
就认为已经完成。一旦完成所有小功能,原始的整体tick
功能即被删除。
不幸的是,演示者似乎没有意识到这种方法导致四个*_tick
功能中的三个出现错误(另一个是空的!)。在某些极端情况下,*_tick
功能的行为与原始tick
功能不同。例如,@days_remaining <= 0
in brie_tick
应该是< 0
-所以brie_tick
当用days_remaining == 1
和调用时不能正常工作 quality < 50
。
这里出了什么问题?这是否是测试失败-因为没有针对这些特殊情况的测试?还是重构失败-因为代码应该已经逐步进行了转换,而不是从头开始重写?