编程的97件事——6、在重构之前
在重构之前
每个程序员都会在某些时候需要重构已存在的代码。但在这样做之前请想想下面的问题,这会省去你和其他人很多时间(和痛苦):
- 开始重构的最佳时机是审查代码库和代码库的测试代码的时候。这时你明白当前代码的优点和不足,这可以确保你重构时保持代码的优秀特性并避免上个版本犯下的错误。我们都以为自己会比现存系统做得更好,结果并没有更好,还可能更糟…这是因为我们没有从前人的错误中吸取教训。
- 避开推到重来的诱惑。复用的代码越多越好。无论这些代码多么丑陋,这些代码毕竟是被测试和复查过的。丢弃旧代码,尤其是产品代码,意味着你丢弃经年累月测试、实战检验的代码,这些代码可能包含某些巧妙的设计,修复了一些你没有察觉到的bug。如果你不考虑这些,你新写的代码可能会重现一些旧代码已经修复的bug。这样的做法浪费了这么多年的时间和努力积攒的知识。
- 多次增量修改要好于一次大改。通过诸如测试结果一类的反馈,增量测试能够让你更容易把握改动对系统带来的影响。一次修改过后测试出上百条错误可一点都不有趣。这会带来焦虑和压力,反过来使你更容易作出错误的决定。而只有几条测试错误则好处理得多,使你的重构过程更加可控。
- 每次迭代之后,确保本次迭代通过测试是非常重要的。如果原来的测试代码不能覆盖本次修改,就增加新的测试以保证覆盖率。在没有充分的考虑之前不要丢弃旧代码的测试。也许表面上这些测试已经不适用你的新设计了,但刨根问底地了解这些测试存在的原因是值得的。
- 不要让你的喜好和自我成为你的障碍。如果一个东西没坏,为什么要修它呢?代码的风格和结构不对你的胃口并不能构成重构的理由。自认为比前作者能写出更好的程序也不能成为你进行重构的理由。
- 新技术作为重构的理由是不够的。最糟糕的重构理由之一就是当前代码使用的技术比起我们现在的酷炫技术已经落伍了,而我们觉得使用新的编程语言和框架能使功能实现得更优雅。除非通过成本——收益分析我们能得出使用新的语言和框架能使系统在功能、稳定性和效率上都有显著的提高,否则最好先别动手。
- 记住人是会犯错的。重构并不总能保证新代码就一定比旧的更好,甚至不能保证和旧的一样好我曾目睹和参与过一些失败的重构。这并不美好,但人生就是这样。
Before You Refactor
At some point every programmer will need to refactor existing code. But before you do so please think about the following, as this could save you and others a great deal of time (and pain):
- The best approach for restructuring starts by taking stock of the existing codebase and the tests written against that code. This will help you understand the strengths and weaknesses of the code as it currently stands, so you can ensure that you retain the strong points while avoiding the mistakes. We all think we can do better than the existing system... until we end up with something no better — or even worse — than the previous incarnation because we failed to learn from the existing system's mistakes.
- Avoid the temptation to rewrite everything. It is best to reuse as much code as possible. No matter how ugly the code is, it has already been tested, reviewed, etc. Throwing away the old code — especially if it was in production — means that you are throwing away months (or years) of tested, battle-hardened code that may have had certain workarounds and bug fixes you aren't aware of. If you don't take this into account, the new code you write may end up showing the same mysterious bugs that were fixed in the old code. This will waste a lot of time, effort, and knowledge gained over the years.
- Many incremental changes are better than one massive change. Incremental changes allows you to gauge the impact on the system more easily through feedback, such as from tests. It is no fun to see a hundred test failures after you make a change. This can lead to frustration and pressure that can in turn result in bad decisions. A couple of test failures is easy to deal with and provides a more manageable approach.
- After each iteration, it is important to ensure that the existing tests pass. Add new tests if the existing tests are not sufficient to cover the changes you made. Do not throw away the tests from the old code without due consideration. On the surface some of these tests may not appear to be applicable to your new design, but it would be well worth the effort to dig deep down into the reasons why this particular test was added.
- Personal preferences and ego shouldn't get in the way. If something isn't broken, why fix it? That the style or the structure of the code does not meet your personal preference is not a valid reason for restructuring. Thinking you could do a better job than the previous programmer is not a valid reason either.
- New technology is insufficient reason to refactor. One of the worst reasons to refactor is because the current code is way behind all the cool technology we have today, and we believe that a new language or framework can do things a lot more elegantly. Unless a cost–benefit analysis shows that a new language or framework will result in significant improvements in functionality, maintainability, or productivity, it is best to leave it as it is.
- Remember that humans make mistakes. Restructuring will not always guarantee that the new code will be better — or even as good as — the previous attempt. I have seen and been a part of several failed restructuring attempts. It wasn't pretty, but it was human.
注:本次更新间隔比较久,主要是有别的事要忙。同时自己也学习了一些翻译的知识,力求提高翻译质量。顺便说下,本篇是本人第一次使用专业的翻译软件~