我已经习惯通过引入编译错误来做一些重构.例如,如果我想从我的类中删除一个字段并使其成为某些方法的参数,我通常首先删除该字段,这会导致该类的编译错误.然后我会将参数引入我的方法,这将打破调用者.等等.这通常给我一种安全感.我还没有读过关于重构的任何书籍,但我曾经认为这是一种相对安全的方法.但我想知道,它真的安全吗?或者这是一种糟糕的做事方式?
重构时我从不依赖简单的编译,代码可以编译但可能已经引入了bug.
我认为只为你想要重构的方法或类编写一些单元测试是最好的,然后通过在重构后运行测试你将确保没有引入错误.
我不是说去测试驱动开发,只是编写单元测试来获得你需要重构的必要信心.
对于静态编译的语言,这是一种常用且有用的技术.您正在做的一般版本可以说明如下:
当您对可能使该模块的客户端中的某些用途无效的模块进行更改时,请以导致编译时错误的方式进行初始更改.
有各种各样的推论:
如果方法,函数或过程的含义发生更改,并且类型也未更改,则更改名称.(当您仔细检查并修复所有用途时,您可能会更改名称.)
如果将新案例添加到数据类型或枚举的新文字,请更改所有现有数据类型构造函数或枚举文字的名称.(或者,如果您足够幸运,有一个编译器可以检查案例分析是否详尽无遗,那么有更简单的方法.)
如果您使用的是超载语言,请不要只更改一个变体或添加新变体.您可能会以不同的方式以静默方式解决重载问题.如果你使用重载,很难让编译器以你希望的方式为你工作.我知道处理重载的唯一方法是全局推理所有用途.如果您的IDE无法帮助您,则必须更改所有重载变体的名称.不愉快.
您真正在做的是使用编译器来帮助您检查代码中可能需要更改的所有位置.
我没有看到任何问题.它是安全的,只要你在编译之前没有提交更改,它就没有长期影响.此外,Resharper和VS拥有的工具可以让您轻松完成整个过程.
你在TDD的另一个方向上使用了一个类似的过程 - 你编写的代码可能没有定义的方法,导致它无法编译,然后你编写了足够的代码来编译(然后传递测试,等等......)
当您准备阅读有关该主题的书籍时,我推荐Michael Feather的" 有效使用遗留代码 ".(由非作者添加:Fowler的经典着作" 重构 " - 以及重构网站可能很有用.)
他谈到在进行更改之前确定您正在使用的代码的特征,并执行他所谓的临时重构.这是重新发现以找到代码的特征,然后抛弃结果.
你正在做的是使用编译器作为自动测试.它将测试您的代码是否编译,但如果行为因您的重构而发生更改或者是否存在任何副作用,则会进行测试.
考虑一下
class myClass { void megaMethod() { int x,y,z; //lots of lines of code z = mysideEffect(x)+y; //lots more lines of code a = b + c; } }
你可以重构这个添加
class myClass { void megaMethod() { int a,b,c,x,y,z; //lots of lines of code z = addition(x,y); //lots more lines of code a = addition(b,c); } int addition(int a, b) { return mysideaffect(a)+b; } }
这会起作用,但第二个附加因为调用方法会有误.除了编译之外,还需要进一步的测试.