什么时候重构变得不值得了?
假设您有一个程序当前按预期方式运行。 该应用程序背后的代码非常糟糕,占用大量内存,不可扩展,并且需要进行大量重写才能实现功能上的任何更改。
在什么时候重构会变得比完全重建更不合乎逻辑?
Say you have a program that currently functions the way it is supposed to. The application has very poor code behind it, eats up a lot of memory, is unscalable and would take major rewriting to implement any changes in functionality.
At what point does refactoring become less logical then a total rebuild?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
Joel 就这个主题写了一篇很好的文章:
你永远不应该做的事情,第 1 部分
我从中得到的重要教训是,尽管旧代码很糟糕,会伤害你的眼睛和美感,但很有可能很多代码正在修补未记录的错误和问题。 也就是说,它嵌入了很多领域知识,您将很难或不可能复制它。 你会不断地遇到疏忽的错误。
我发现一本非常有用的书是 Michael C. Feathers 的有效处理遗留代码 。 它提供了处理甚至真正丑陋的遗留代码的策略和方法。
Joel wrote a nice essay about this very topic:
Things You Should Never Do, Part 1
The key lesson I got from this is that although the old code is horrible, hurts your eyes and your aesthetic sense, there's a pretty good chance that a lot of that code is patching undocumented errors and problems. Ie., it has a lot of domain knowledge embedded in it and it will be difficult or impossible for you to replicate it. You'll constantly be hitting against bugs-of-omission.
A book I found immensely useful is Working Effectively With Legacy Code by Michael C. Feathers. It offers strategies and methods for approaching even truly ugly legacy code.
重构相对于重建的好处之一是,如果您可以逐步(即增量)进行重构,则可以在整个系统的上下文中测试增量,从而加快开发和调试速度。
旧的和已部署的代码,即使丑陋且缓慢,也具有经过彻底测试的好处,但如果从头开始,这种好处就会消失。
增量重构方法还有助于确保始终有可以交付的可用产品(并且它正在不断改进)。
网络上有一篇关于 Netscape 6 是如何从头开始编写的好文章,它在商业上是明智的坏主意。
One benefit of refactoring over rebuilding is that IF you can do refactoring step by step, i.e. in increments, you can test the increments in the context of the whole system, making development and debugging faster.
Old and deployed code, even when ugly and slow, has the benefit of having been tested thoroughly, and this benefit is lost if you start from scratch.
An incremental refactoring approach also has helps to ensure that there is always a product available which can be shipped (and it's improving constantly).
There is a nice article on the web about how Netscape 6 was written from scratch and it was business-wise a bad idea.
罗伯特·L.格拉斯建议
Robert L. Glass suggests that
好吧,最简单的答案是,如果重构所需的时间比重建所需的时间更长,那么您应该重建。
如果这是一个个人项目,那么您可能无论如何都想重建它,因为从头开始构建您可能会比从重构中学到更多,这是个人项目的一大目标。
然而,在一个时间有限的专业环境中,从长远来看,你应该始终选择让公司花费最少的钱(获得相同回报)的方案,这意味着选择花费更少时间的方案。
当然,情况可能比这更复杂一些。 如果其他人可以在重构过程中处理功能,那么这可能是比让每个人都等待构建全新版本更好的选择。 在这种情况下,重建可能比重构花费的时间要少,但您需要考虑整个项目和项目的所有贡献者。
Well, the simplest answer is if it will take longer to refactor than it will to rebuild, then you should just rebuild.
If it's a personal project then you might want to rebuild it anyway as you will probably learn more from building from scratch than you would from refactoring, and that's one big objective of personal projects.
However, in a professional time-limited environment, you should always go with whatever costs the company the least amount of money (for the same payoff) in the long run, which means choosing whichever takes less time.
Of course, it can be a little more complicated than that. If other people can be working on features while the refactoring is being done, then that might be a better choice over having everyone wait for a completely new version to be built. In that case rebuilding might take less time than just the refactoring would have taken, but you need to take the entire project and all contributors of the project in to account.
当您花费更多时间进行重构而不是实际编写代码时。
When you spend more time refactoring than actually writing code.
当软件没有完成它应该做的事情时。 当且仅当功能“按预期”时,重构(更改代码而不更改功能)才有意义。
At the point where the software doesn't do what it's supposed to do. Refactoring (changing the code without changing the functionality) makes sense if and only if the functionality is "as intended".
如果您有时间完全重建应用程序,不需要逐步改进功能,并且不希望保留任何现有代码,那么重写当然是一个可行的选择。 另一方面,您可以使用重构来进行增量重写,通过慢慢地将现有函数替换为编写得更好且更高效的等效函数。
If you can afford the time to completely rebuild the app, don't need to improve functionality incrementally, and don't wish to retain any of the existing code then rewriting is certainly a viable alternative. You can, on the other hand, use refactoring to do an incremental rewrite by slowly replacing the existing functions with equivalent functions that are better written and more efficient.
如果应用程序非常小,那么您可以从头开始重写。 如果应用程序很大,就不要这样做。 逐步重写它,一次一步地验证您没有破坏任何东西。
应用程序就是规范。 如果你从头开始重写它,你很可能会遇到很多阴险的错误,因为“没有人知道在这种非常特殊的情况下对此函数的调用应该返回 3”(未记录的行为......)。
从头开始重写总是更有趣,这样你的大脑可能会欺骗你,让你认为这是正确的选择。 小心点,很可能不是。
If the application is very small, then you can rewrite it from scratch. If the application is big, never do it. Rewrite it progressively, one step at a time validating you didn't break anything.
The application is the specification. If your rewrite it from scratch you will most likely run into a lots of insidious bugs because "no one knew that the call to this function was supposed to return 3 in that very specific case" (undocumented behaviour...).
It's always more fun to rewrite from scratch so your brain might trick you into thinking it's the right choice. Be careful, it's most likely not.
我过去曾使用过此类应用程序。 我发现的最好的方法是渐进的:当您编写代码时,找到多次完成的事情,将它们分组到函数中。 准备一个笔记本(你知道,是一个真正的笔记本,里面有纸、铅笔或钢笔),以便你可以标记你的进度。 将其与 VCS 结合使用,而不是代替它。 该笔记本可用于提供您在重构过程中创建的新函数的概述,而 VCS 当然会填补详细信息的空白。
随着时间的推移,您将把大量代码合并到更合适的位置。 在这段时间里,代码重复几乎是不可能的,因此请尽你所能,直到你可以真正开始重构过程,审核整个过程。代码库并将其作为一个整体进行处理。
如果您没有足够的时间来完成该过程(这将需要很长时间),那么使用测试优先的方法从头开始重写可能会更好。
I've worked with such applications in the past. The best approach I've found is a gradual one: When you are working on the code, find things that are done multiple times, group them together in functions. Keep a notebook (you know, a real one, with paper, and a pencil or pen) so that you can mark your progress. Use that in combination with your VCS, not instead of it. The notebook can be used to provide an overview of the new functions you've created as part of the refactoring, and the VCS of course fills in the blanks for the details.
Over time, you will have consolidated a lot of code into more appropriate places. Code duplication during this period of time is going to be next to impossible, so just do it as best as you can until you've reached a point where you can really start the refactoring process, auditing the entire code base and working on it as a whole.
If you've not enough time for that process (which will take a very long time), then rewriting from scratch using a test-first approach is probably better.
一种选择是编写单元测试来覆盖现有应用程序,然后开始一点一点地重构它,使用单元测试确保一切都像以前一样工作。
在理想的情况下,您已经对该程序进行了单元测试,但考虑到您对应用程序质量的评论,我猜您没有......
One option would be to write unit tests to cover the existing application and then start to refactor it bit by bit, using the unit tests to make sure everything works as before.
In an ideal world you'd already have unit tests for the program, but given your comments about the quality of the app I'm guessing you don't...
没有文档,没有原创作者,没有测试用例,还有一堆遗留的错误。
No document, no original writer, no test case, and a bunch of remaining bugs.
鲍勃叔叔参与进来具有以下内容:
Uncle Bob weighs in with the following:
当我继承的代码非常糟糕时,我在小的增量更改方面运气不佳。 从理论上讲,小增量方法听起来不错,但实际上,它最终得到的是一个更好但仍然设计不佳的应用程序,每个人都认为现在是您的设计。 当事情发生故障时,人们不再认为这是因为以前的代码,现在它变成了你的错。 因此,我不会使用“重新设计”、“重构”或任何其他词来暗示经理类型你正在按照自己的方式改变事情,除非我真的打算按照我的方式去做。 否则,即使您可能已经解决了数十个问题,但仍然存在(但未被发现)的任何问题现在都将归因于您的返工。 并且请放心,如果代码很糟糕,那么您的修复将发现更多以前被简单忽略的错误,因为代码一开始就很糟糕。
如果你真的知道如何开发软件系统,那么我会对整个系统进行重新设计。 如果您不真正知道如何设计好的软件,那么我会说坚持小的增量更改,否则您最终可能会得到与原始代码一样糟糕的代码库。
重新设计时经常犯的一个错误是人们忽略了原始代码库。 然而,重新设计并不一定意味着完全忽略旧代码。 旧代码仍然必须执行新代码必须执行的操作,因此在许多情况下,您需要的步骤已经在旧代码中。 在重新设计系统时,复制并粘贴然后调整会产生奇迹。 我发现在许多情况下,重新设计和重写应用程序以及从原始代码中窃取片段比小的增量更改更快、更可靠。
I’ve not had much luck with small incremental changes when the code I inherit is really bad. In theory the small incremental approach sounds good, but in practice all it ends up with is a better, but still poorly designed application that everyone thinks is now YOUR design. When things break, people no longer think it is because of the previous code, it now becomes YOUR fault. So, I would not use the word redesign, refactor or anything else that implies to a manager type that you are changing things to your way unless I was really going to do it my way. Otherwise, even though you may have fixed dozens of problems, any problems that still existed (but weren’t discovered) are now going to be attributed to your rework. And be assured that if the code is bad then your fixes will uncover a lot more bugs that were simply ignored before because the code was so bad to begin with.
If you truly know how to develop software systems then I would do a redesign of the whole system. If you don’t TRULY know how to design GOOD software then I’d say stick with the small incremental changes as you may otherwise end up with a code base that is just as bad as the original.
One mistake that is often made when redesigning is that people ignore the original code base. However, redesign does not have to mean totally ignore the old code. The old code still had to do what your new code has to do, so in many cases the steps you need are already in the old code. Copy and Paste then tweak works wonders when redesigning systems. I have found that in many cases, redesigning and rewriting an application and stealing snippets from the original code is far quicker and much more reliable than small incremental changes.