我回想起乔尔斯波斯基的文章约从未从头重写代码。 为了总结他的论点:代码不生锈,虽然它可能不经过许多维护版本看起来很漂亮,如果它的工作原理,它的工作原理。 最终用户并不关心代码是多么可爱。
你可以在这里阅读文章: 事情你应该永远不会做
我最近接手一个项目,并通过他们的代码后看,这是很可怕的。 我立刻想到我之前已经建立原型,并明确表示,它不应该被用于任何生产环境。 不过,当然,人们不听。
该代码被编译为一个网站,没有任何的顾虑,没有单元测试和代码重复到处分离。 无数据层,没有实际的业务逻辑,除非你在App_Code文件一堆类。
我提出的建议向利益相关者,虽然我们应该保持现有的代码,并做bug修复版本,以及一些小的功能版本,我们应该开始考虑和与关注明确分离测试驱动开发立即对其进行改写。 我考虑去的ASP.NET MVC路线。
我唯一担心的是,当然,时间的长短可能需要从头开始重写。 它不完全是复杂的,其成员等轧机Web应用程序的运行漂亮..
有任何你遇到类似的问题? 你把任何特定的步骤?
更新:
所以..我是怎么最终决定做什么? 我把马特的做法,并决定重构的许多领域。
虽然我在这个项目上[资金,政治,等等等等]不再工作,我认为它给了我一些巨大的洞察到一些项目怎么不好可写,和步骤的一个开发人员可以采取使事情变得更干净,可读性和公正平跟随着时间的推移小的,渐进的步骤出更好。
Answer 1:
正因为它拥有所有这些问题现在并不意味着它有继续拥有他们。 如果你发现自己在做,可以从中受益,比如,一个新的数据层系统中的特定bug修复,然后创建一个新的数据层。 只是因为整个网站不使用它并不意味着你不能开始使用一个。 重构,你在你的错误修复需要。 并确保您了解到底是什么代码做什么你改变它之前。
问题的代码重复? 拉出来为一类或实用工具库,在需要修复的错误在重复码的中心位置下一次。
而且,正如已经被其他反应提到 - 现在就开始写测试。 这可能是很难如果代码是耦合的,因为它的声音,但你可能开始的地方。
没有充分的理由重写工作代码。 但是,如果你已经修复bug,没有理由你不能返工与“更好”的设计代码的特定部分。
Answer 2:
乔尔的文章真的说明了一切。
基本上从来没有。
由于乔尔指出:你只是失去太多从头开始做。 这可能会花费更长的路比你想象的,什么是最终的结果? 东西基本上做同样的事情。 那么什么是商业案例 ,这样做呢?
这是一个很重要的一点:它的成本钱从头开始写东西。 您将如何收回这笔钱? 许多程序员忽略了这一点,只是因为他们不喜欢的代码 - 有时有正当理由,有时没有。
Answer 3:
这本书的事实和错觉软件工程指出这样一个事实:“重复使用的代码的修改特别容易出错。如果组件超过20%到25%将被修订,这是更有效从头开始重写。 “ 这些数字来自对主题进行了一些统计研究。 我认为数字可能由于代码库的质量各不相同,所以在你的情况下,它似乎是更有效和更有效地采取这一声明考虑从头开始重写。
Answer 4:
我曾经有过这样一个应用程序,并重写是非常有益的。 但是,你应该尝试aviod的“改善”的陷阱。
当你改写一切,这是非常诱人的增加新的功能并修复了一些你没有胆量触碰长期存在的问题。 这可能会导致功能蔓延和扩展也需要重写极大的时间。
请确保你决定究竟会改变什么,只会被改写- 提前 。
Answer 5:
我不同意这篇文章有点。 在大多数情况下乔尔正确的,但也有相反的例子,有时(即使很少)重写是一个好主意指示。 例如,
- Windows NT的(脱离了旧的DOS代码库了。在此基础上建成的Win2k,WinXP的和即将推出的Win7是的,Vista的了。窗户的旧基上的最后一个版本是臭名昭著的WinME的)
- 的Mac OS X(重建他们的旗舰产品上的FreeBSD)
- 许多情况下,竞争对手取代的事实标准。 (例如,相对于Excel的莲花123)
我相信,乔尔的说法主要是基于现有版本,可以在事后加以改进得相当好编写的代码。 通过一切手段,如果你继承的代码是真的如此糟糕,推动重写 - 有一些可怕的东西在那里。 如果这是在所有的容忍和速度较慢的性能非常好,逐步引入新的东西。
Answer 6:
我一直是一个小的专门的团队已重新编写了代码,包括前面的代码的逆向工程业务规则的一部分。 原来的应用程序是用C语言编写的web服务++(定期崩溃和严重内存泄漏)和ASP.Net 1.0 web应用程序和替换是一个C#2.0 ASMX基于web的服务和使用Ajax一个ASP.Net 2.0 web应用程序。 这说的一些事情的团队做和管理层解释
- 我们支持在生产现有的代码库,直到新的代码准备好了。
- 管理层同意重写(第一版)将引入任何新功能,但只实现现有功能。 我们在结尾加上只有1-2个新功能。
- 小团队由经验丰富的开发人员提供出色的理解能力和合作。
- 这是很难获得C ++人才组织和C#被看作是未来维护一个更好的选择。
- 我们同意积极的时间表,但在同一时间有信心和充满活力的工作在C#2.0,ASP.Net 2.0等。
- 我们有一个团队的领导者,从上层管理保护我们,我们跟着SCRUM喜欢的过程。
该项目是非常成功的。 这是非常稳定和更好的表演。 后来也就更容易增加新的功能。 所以,我认为,重写代码可以成功地完成赋予的权利资源和环境。
Answer 7:
只有一个半合法的理由浮现在脑海:政治。
我不得不从头开始重写代码库,而且它与政治有关。 一般来说,前编码谁管理的代码库都不好意思源代码发布到新的团队,刚刚被录用。 她认为,该代码的每一个批评是作为一个人的她的批评,并作为一个结果,当她被强迫她只发布的代码给我们的休息。 她是唯一的人一起源库管理权限,每当她一直要求释放所有的源,她威胁要退出,并采取所有她的代码的知识和回家。
这个代码库是15岁以上,并有各种不同的人有各种不同风格的卷积和扭曲。 这些显然参与评论或规格,款式无至少,在一小部分,她的发布给我们。
对于仅能提供部分代码和一个期限,我被迫做了完全重写。 我得到的结果大叫,因为有人声称我造成了严重的延迟,但我只是不停地我的头,并得到它完成,而不是争论。
政治可以是一个巨大的痛苦。
Answer 8:
我一直在正是这种情况,但不是完全重写我的工作通过重构过程中改变的事情。 我遇到的问题是我的工作与 - 可怕的,很多页面的代码非常复杂的特殊情况下驱动的开发都基于IF-案件和令人费解的正则表达式分层回过大约十年无计划的发展和扩张。
我的目标是得到它的功能重构功能,因此,它会提供相同的输入相同的输出,但工作更干净平稳的发动机罩下,以促进未来增长和提高性能。 一般的解决办法是干净,快捷,但在代码中的固定工作刚刚得到越来越多的困难和复杂晦涩特殊情况下由系统解析的文件开始展现自我,我的漂亮干净的代码将产生只是输出一点点从原来做过什么太大的不同(这是网页,所以不同量的空白可能会导致各种在老版本的IE布局的问题),在小的和模糊的方式。
我不知道是否曾经得到used-返工的代码,我离开了公司它必须充分integrated-的机会之前,但我对此表示怀疑。 为什么要使用二十行的代码时,1500“如果”语句和三线的正则表达式可以做同样的工作吗?
Answer 9:
在一个完全重写的一个危险是,你的工作是不断上线。 你说是不是有助于底线成本。 吸住的代码是真实让钱生钱的代码。
但是,如果你在固定的时刻现有的代码一块,你是谁知道赚钱机器是如何工作的人。
Answer 10:
我的回答是:从头开始尽可能多地改写。
我已经花了我的大部分职业生涯的继承谁是由经理人认为是“摇滚明星”粪我们尊称“程序”,由年轻的,缺乏经验的程序员编写的蒸桩。 这些东西一般是不固定的,你最终将花费10倍的努力让他们一起,你会花刚刚从地上爬起来重写他们举步维艰。
但我也通过定期重写我自己的工作中受益匪浅。 每个重写是一个机会,做不同的事情,还有可能提高,你应该能够重复使用至少旧版本的某些部分。
话虽这么说,并不是所有的重写是一个好主意。 Windows Vista中,例如。
Answer 11:
在某些时候,你必须减少你的损失。 如果您刚刚继承了这个代码库,您可能认为有意想不到的后果的变化,并且由于缺乏测试,他们将几乎不可能找到。
最起码,立即开始编写测试。
Answer 12:
而是从头开始一个完全重写的你要开始重构小步骤的代码基础,同时引入的单元测试。 例如
- 将重复的代码到一个公共类试验resuse整个项目
- 引入接口来创建单独的可测试的模块。 然后,您可以重构接口背后的实现,同时依靠你的测试,以确保您不会破坏任何东西。
Answer 13:
我宁愿一点做事情有点,例如,创建一个后台与数据模型数据库,你在这些领域(即用户登录先,然后用户管理,等等),并调整现有的前工作末端使用新的后端(接口驱动的,所以你也可以添加测试)。 这将保持与可能的无证调整和行为,你将不会被从头开发,而在关注一些分离将复制现有的代码。
不久后,你就已经迁移代码基数的60%,使用新的后端不工作作为一个正式项目,只是维护,所以你会在一个更好的位置,主张发展时间做其他40 %,并且一旦完成现有的前端类将在大小和复杂性被大大降低。 一旦它被完全移植,你就可以重新使用新的后端模型和控制器组件,如果你有机会实现一个新视图的时间。
Answer 14:
通过编写技术规格开始。 如果代码是可怕的,那么我敢打赌,没有一个真正的规范无论是。 所以写了全面细致的规范 - 你需要,如果你想从头开始重写这么写一个规范,所以时间是一个很好的投资。 小心包括有关功能的所有细节。 既然你能调查应用程序的实际行为,这应该很容易。 随意包括改进建议,但一定要抓住当前行为的所有细节。
作为调查的一部分,你可以考虑写一些自动化测试系统调查和文件预期行为。 专注于黑盒/集成测试,而不是单元测试(该代码可能不会允许反正如果它是丑陋的)。
当你有这个天赋,你可能会发现,应用程序实际上是要复杂得多你的第一印象,并重新从头开始重写。 如果你决定,而不是逐步重构,规范和测试将帮助你很多。 但是,如果你仍然决定继续前进,重写,那么你有一个很好的规范,从现在的工作,以及一套集成测试,这将泰利你当你的工作就完成了。
Answer 15:
我认为这取决于两个因素:
1)如何有缺陷遗留代码库的基本设计,
2)的时间,将采取做重写。
1)公司工作,我为曾经有一个可怕的代码库的设计,这使得重构真的很难,因为我们不能在同一时间重构一个位,主要的问题不是个别类和函数但与整体设计。 因此,重构方法,将是非常困难的。 (如果整体设计还是不错的,但是,比如说,各个功能是300线长,需要分手,然后重构是有道理的)。
2)尽管大量的代码,很令人费解,运行的进程。 我们的引擎没有做那么多。 所以重写不是很久。 有时候,管理者并没有意识到几十万行代码的该功能可以在很短的时间内重建。
我们试图解释这对我们的CTO(小公司),但他仍然认为重写将很危险的,所以我和我的同事在大约四个周末重写了引擎的基本功能。 然后展示给我们的CTO终于被说服。
现在,如果建筑的基本功能,会使我们半年,我们不会有多大的一个论据。
Answer 16:
还有经济学,说冲突的声明,
决不占沉没成本
沉没成本,根据维基百科( https://en.wikipedia.org/wiki/Sunk_cost ):
在经济学和商业决策,沉没成本是已经发生且无法收回成本。
当沉没成本加上政治压力或个人的自我(什么经理想成为承认自己做了一个错误的决定或者没有正确地监测的结果之一,即使它是不可避免的或他们的直接控制的?),它导致所谓的承诺的升级 (情况https://en.wikipedia.org/wiki/Escalation_of_commitment ),其被定义为:
行为模式,其中一人或一组,当面对一些决策,行动和投资日益负面的结果,将继续而不是改变他们的课程,东西是不合理的,但与先前作出的决定和行动一致。
请问这个适用于代码?
有一个相当长的职业生涯,现在的软件开发人员,一个共同的思路,我发现的是,当面对一个具有挑战性的或丑陋的代码库(即使它是我们从两年前开始自己的),我们的第一反应是想扔淘汰旧的,丑陋的代码,并从头开始重写。 如果它是一个熟悉的代码库,那么这通常是一个事实,即我们现在更熟悉的项目和业务需求的陷阱比我们当我们开始这个项目,所以我们(也许是下意识的)渴望有机会诞生通过与完美消除他们解决我们过去的罪孽。 如果它是一个陌生的代码库,我们经常倾向于过度简化所面临的原始开发商所面临的挑战,掩饰“小细节”赞成“大画面”的建筑层次思维,常吹由于预算和时间框架缺乏该代码最初旨在解决商业案例的复杂细节的理解。
再有就是技术债务,其中,就像金融债务,能够而且将会累积到一个代码库成为技术上资不抵债点的整个概念。 越来越多的时间和资源被投入到故障排除错误,灭火,和过于挑战改进前向进展变得昂贵,困难和危险的程度。 项目的缺陷而需要更长的时间和更长被拉离项目工作来解决生产问题。 几个小时后“事件”开始成为代替一些罕见的昙花一现预期操作。 相反,退一步,并开始做正确的事情,以促进我们未来的生产率(和生活质量),我们发现自己在我们被迫以满足最后期限添加越来越多的技术债务的位置 - 技术等同于服用信用卡上的现金垫款再拍卡上的最低还款额。
这一切都这样说,这也不意味着我们应该尽可能地重写,我们也不应该避免重写不惜一切代价工作代码。 两种极端都是潜在的浪费,而后者则往往会造成承诺的不断升级(由于不惜一切代价, 用完全不顾成本意味着,即使这些费用完全超过了好处 )。 需要怎样发生的成本和重写代码与进行增量改进的利益的客观评估。 我们面临的挑战是找到一个人的专业知识和客观性,既要做出这样的决定正确。 对于我们开发者,我们一般都偏向重写,因为它往往是很多比一些蹩脚的传统代码库的工作更有趣,更吸引人。 业务经理往往偏向另一个方向,因为重写产生一些未知很少感知的直接好处。 的结果通常是不存在真正的决定,其中的默认然后继续直到一些情况必要定向移(或显影剂隐蔽重写代码,通常得到一个非常好的用于它)转储小时到现有的代码。
我对有些人挽救,尽管丑陋的代码库工作。 他们没有按照惯例和标准,未使用的模式,不是很漂亮,但他们履行自己的预期功能相当不错,具有足够的灵活性,他们可以进行修改,以满足预期的未来应用的预期寿命需要。 虽然不是魅力四射,这是完全可以接受的,以保持该代码还活着,同时使增量改进当机会出现。 这样做不是很期待其他否则会产生多少效益。 我要说的是,大多数代码关于其应我重写这个? 问题是属于这一类,我发现自己解释到对球队的初级开发人员认为,虽然这将是非常有趣改写YetAnotherLineOfBusinessApp在{在此插入whizzbang框架},这样既不需要或希望,这里有一些方法我们可以改善它。
我还参与了那名无望的代码库。 这些是几乎在第一时间推出,通常远远落后进度,并在缩减功能状态的应用程序。 他们写的任何人,但原来的开发者必须理解什么代码最终做任何机会的方式。 我称此为“只读”的代码。 一旦它被写,任何试图改变可能导致不明原因的全身难懂的失败,导致恐慌的是并没有别的比来教育什么是真正发生在一个巧妙地命名变量的当前开发商的目的大规模单片代码构造的批发重写obj_85
由时间执行到嵌套深7级线1209 if... else...
, switch
和foreach...
在某处声明DoEverythingAndMakeCoffee(...)
方法。 尝试重构失败这段代码的结果。 每路你跟着导致另一个挑战,更多的路径,然后路径分支,再绕回到以前的路径,两周一个类的低头重构后,你意识到,虽然也许更好的封装,新的代码几乎与怪诞的和模糊的旧代码,可能包含更多的错误,因为你重构一下原来的意图是完全不清楚,而且不知道什么确切的商业案例,导致原来的灾难摆在首位,你不能肯定你已经完全复制的功能。 进步是几乎不存在,因为代码库的翻译是几乎不可能有什么东西那么无辜被重命名变量或使用正确类型产生意想不到的副作用的指数数量。
试图改善像上面的代码库是徒劳无益的。 重构通常导致80%重写反正,并且最终结果是不通的80%的改善的附近。 你最终的东西,这是非常不一致,新的代码有很多的妥协是有互操作性的遗留代码的利息(其中一半是不必要的,因为新的代码所需的遗留代码与互操作,以实现后来被重构反正出)。 只有两种路径可以遵循...继续在“修复”和修改黑客累积技术债务,同时希望该应用程序已被弃用(或者你会转移到其他项目中)它缩短了其自身重量下之前,或有人做商业决策,并采取做一个完全重写的风险。 我讨厌这两个选项,因为它通常意味着等到什么重要的失败或项目进度落后的方式,然后你再花未来三个月晚上和周末试图让一些呼吸,可能不应该在还活着的首位。
那么,你如何决定?
- 效果如何现有的代码工作? 它是可靠的,相对无缺陷?
- 是人们对我的团队能够理解什么是这个代码用的力气合理程度? 如果我在一个有经验的开发人员带来的,将他/她能够做出这种感觉足以在合理的时间内成为生产力?
- 做什么,应待简单的缺陷,采取地质时间测量来解决; 以至于我们无法取得真正的改进或满足项目的最后期限?
- 是的codebase如此脆弱和预期寿命,使得应用程序的能力,以适应未来的预期的业务需求是非常值得怀疑的?
- 难道已有的代码实际上满足了原始功能要求?
- 您的组织甚至接受应用程序中的投资,或者是有人(特别是有人在组织结构图上一个更高的水平)将被交给自己的* SS的问题?
- 你能提供资金或者基于风险的理由,辅以铁的事实,作出了改写商业案例?
- 如果,时间和重写的成本足足占后(包括制定适当的规格,质量保证测试,生产后的稳定和培训,是否还有意义,开始重写代码(我们的开发人员往往只考虑在条件的编码时间)?
- 你有选择吗? 它甚至有可能对现有的代码来满足需求(因为如果不是,重写巨大的大片将是该项目的一部分,并认为“增强”,而不是一个重写)?
Answer 17:
有一句古老的格言所云:
有坏的代码没有这样的事情。 有没有你想要的是什么,做不仅代码和代码。
关键要知道在那里时,重新写的谎言。 系统是否目前还你想要什么? 如果答案是肯定的,缓慢的,但稳定的改进是你最好的选择。 如果答案是否定的,重新写是你想要的。
让我们再回到乔尔的文章中,他谈到了代码的混乱,但软件是可靠的,并提供了预期值。 相反,如果你有不可靠的代码充满主要的bug,并且没有覆盖所有的用例。 您有同时应该在那里又没有工作,或者只是缺少的东西。 在这种情况下,所有生长出它的小汗毛都没有bug修复,但癌症。
文章来源: When to rewrite a code base from scratch