刚读了有关Big Rewrites的问题,我就想起了一个我一直想回答的问题。

我有一个可怕的项目传给我,它使用Struts 1.0,旧Java表编写具有不一致的关系,或者根本没有关系,甚至没有主键的表也没有要作为主键的字段,但是根本不是唯一的。大部分应用程序都以某种方式“正常工作”。大多数页面被重用(复制粘贴的代码)并进行硬编码。曾经从事该项目的每个人都以一种或另一种形式诅咒它。我正在慢慢尝试个人时间,但是我真的觉得这值得一些专门的资源来实现。阅读有关大型重写的文章后,我有了第二个想法。当我想说服我的上级支持我的重写时,这不好。 (我在一家相对较小的公司中工作,因此该提案可能会得到批准)。

TL; DR
什么时候可以重写答案,您可以使用哪些论据来支持它?

评论

另外,与以下内容有关:programmers.stackexchange.com/questions/20246/…

很老,但是很经典-乔尔(Joel)的“你永远不应该做的事情,第一部分” joelonsoftware.com/articles/fog0000000069.html

这是一个很好的问题。非常相关,这种情况在软件工程中经常发生。

OP仍可以重写他/她经常使用的软件部分。彻底的重新设计显然很烦人,但是Joel Spolsky说的恰恰相反。如果您可以在开始编码之前/继续编码时以某种方式捕获所有/大多数问题,则可以避免“大重写”问题

#1 楼

抱歉,要花很长时间,但这是基于作为多个重写项目的架构师和开发人员的个人经验。

以下情况应该使您考虑进行某种形式的重写。接下来,我将讨论如何确定要执行的操作。


开发人员的启动时间非常长。如果要花更多的时间(根据经验水平)来提升新的开发人员,那么就需要重新设计系统。所谓的提升时间,是指新开发者准备进行第一次提交之前的时间(基于一个小功能)。


大学毕业刚开始-1.5个月/>还是绿色,但在其他项目上工作-1个月之前
中级-2周
经验-1周
高级水平-1天


由于现有架构的复杂性,部署无法自动化
由于现有代码的复杂性,即使是简单的错误修复也花费了太长时间
由于以下原因,新功能花费的时间太长,成本也高代码库的相互依赖性(无法隔离新功能,因此会影响现有功能)
由于现有代码库的相互依赖性,正式的测试周期花费了太长的时间。
太多的用例也要执行几个屏幕。这会给用户和开发人员带来培训问题。
当前系统所需要的技术


具有丰富技术经验的高质量开发人员很难找到
/>已弃用(无法升级以支持较新的平台/功能)
只有一种更具表现力的更高级别的技术可用
维护旧技术的基础架构的成本为太高



这些事情是不言而喻的。什么时候决定是完全重写还是增量重建是比较主观的,因此在政治上也要收费。我可以坚定地说的是,断然声明从来没有一个好主意是错误的。

如果可以逐步重新设计系统,并且您完全支持项目赞助,那么,那么您应该这样做。不过,这就是问题所在。许多系统无法进行增量重新设计。这是我遇到的阻止此情况发生的一些原因(从技术和政治角度而言)。


技术



组件的耦合是如此高,单个组件的更改无法与其他组件隔离。重新设计单个组件不仅会导致相邻组件的级联更改,而且还会间接更改所有组件。
技术堆栈是如此复杂,以至于未来的状态设计需要对多个基础架构进行更改。在完全重写中这也是必要的,但是如果在增量重新设计中需要它,那么您将失去这一优势。
重新设计组件会导致对该组件的完全重写,因为现有的设计太过复杂了没有什么值得保存的。同样,在这种情况下,您会失去优势。


政治


赞助者无法理解渐进式重新设计需要对项目的长期承诺。不可避免地,大多数组织对渐进式重新设计所造成的持续的预算流失失去胃口。这种食欲不振也是不可避免的,但赞助商将更倾向于继续,因为他们不想在一个部分完整的新系统和部分过时的旧系统之间划分。
系统的用户也非常依赖其“当前屏幕”。在这种情况下,您将没有许可证来改善系统的重要部分(前端)。重新设计可以使您避免此问题,因为它们是从新事物开始的。他们仍然坚持要获得“相同的屏幕”,但是您还有更多弹药可以退回。



请记住,重新设计的总成本是递增的通常比完全重写要高,但是对组织的影响通常较小。我认为,如果您可以证明进行重写的理由,并且您拥有超级巨星的开发人员,那么请这样做。

只有在可以确定有完整的政治意愿时,才这样做。这意味着主管人员和最终用户都可以接受。没有它,您将失败。我以为这就是为什么乔尔说这是个坏主意。对于许多建筑师来说,执行官和最终用户的购买看来像是两头独角兽。您必须大胆地出售它,并持续不断地对其进行竞选,直到完成为止。这很困难,您正在谈论的是在某些人不想看到的成功上赢得声誉。

一些成功策略:


如果但是,请勿尝试转换现有代码。从头开始设计系统。否则,您会浪费时间。我从未见过或听说过一个“转换”项目,该项目并没有不幸地结束。
一次将用户迁移到一个团队的新系统。确定在现有系统上遇到MOST痛苦的团队,然后首先迁移它们。让他们通过口口相传的好消息。这样,您的新系统将可以在内部出售。
根据需要设计框架。不要以我花了6个月的时间来构建这个从未见过真正代码的框架开始。
保持您的技术堆栈尽可能小。不要过度设计。您可以根据需要添加技术,但是很难将其淘汰。此外,您拥有的层越多,开发人员要做的事情就越多。不要从一开始就变得很困难。
让用户直接参与设计过程,但不要让他们指示如何做。向他们展示他们,如果他们遵循良好的设计原则,可以给他们更好的东西,从而赢得他们的信任。


评论


我认为Joel的观点是,通过进行重写,您会丢失旧代码中积累的知识。

–quant_dev
2012年1月5日14:11

@quant_dev部分是,但是有时候重写时,您会意识到旧系统中的许多错误是由于旧系统的工作方式引起的,而不是与理想系统的工作方式严格相关的逻辑。

– Tjaart
2012年10月22日16:07

Joel说它将失败,因为在重写过程中,您没有向应用程序添加任何新功能。重写的唯一目的是消除部分或全部技术债务。诚然,这不是一件小事,但是如果您的竞争对手在摆脱技术债务的同时却为其软件添加了新功能,那将是有风险的。

–罗伯特·哈维(Robert Harvey)
2012年10月22日在16:56



我已经使用了满足所有这些条件的代码库,但是Big Rewrite仍然失败,并且通过给我们半执行的“新协议”代码来处理不同于旧混乱的代码,从而使情况变得更糟更易于管理。 IMO,只有在完全不可能进行重构的情况下,才应将所有精力从添加功能和修复错误中转移出来,这些问题如今已使您的客户不堪重负。除非您说的是真正难以理解的代码,否则无法将模块化的位提取出来以方便重用的团队可能无论如何也无法为大型Rw重新构建足够好的架构。

–埃里克·雷彭(Erik Reppen)
13年6月15日在3:31

这是一个有用的答案,但绝非妙不可言,因为它在某些方面给人留下了错误的印象。例如,“请记住,增量重新设计的总成本始终比完全重写高” –该句子中的“始终”一词是错误的,因为“增量重新设计”使您有机会重用至少某些部分现有的设计,而“完全重写”并不能为您提供。我知道,可以肯定的是,因为我实际上是在那种情况下,我们部分完全重写了部分大于100K的LOC应用程序,部分没有。

–布朗博士
2015年12月11日在21:25



#2 楼

我参与了两次大型重写。首先是一个小项目。第二个是软件公司的主要产品。

有几个陷阱:


重写总是比预期花费更长的时间。
重写没有为客户提供直接的效果/收益。
用于重写的功能不支持客户。
除非拥有100%的文档,否则您将无法进行重写。

重写很少是真正的答案。您可以重构很多代码而不会丢失任何内容,也没有太大的风险。

如果您要切换到另一个,则重写可能是答案。语言或平台。
您正在切换框架/外部组件。
现有的代码库不再可维护。

但是我强烈建议使用重构的缓慢方法。这样风险较小,可以使客户满意。

评论


+1为重构方法。很多时候,没有足够的时间或工时来重写和维护现有系统。

–瑞安·海斯(Ryan Hayes)
2010-09-22在12:20

@John:作为一名高管,我很难为我的销售团队尚未获得客户的应用程序进行重写。老实说,我会给它一定的时间,然后决定要怎么做。如果没有兴趣,我会把整个东西扔掉,然后选择其他事情去做。

–NotMe
2010-09-22在22:13

我最近用Java重写了Visual Basic应用程序。这使得它可以在Windows(无Java GUI)下作为服务运行-对客户有利。

–user1249
2011年4月2日在18:04

“重写对客户没有直接的影响/好处”-这通常是一个神话,因为较新的框架提供了“内置的”许多生产力增强功能,这些增强功能要么无法实现,要么实施成本太高。一个示例,将vb6应用程序升级到.net应用程序,使用户可以打开较大的文件(由于采用64位架构),因此这意味着最终用户不必人为地破坏工作。

–斯蒂芬
2015年6月1日,下午3:28

@Stephen是对的,但这等于说为Playstation 4编写的游戏比为Playstation 1编写的游戏具有更好的图形资源。大多数服务器应用程序,Web服务和后端批处理处理器通常不会获得收益除了给开发人员本身带来的好处外,还有其他好处。

– Kain0_0
4月7日下午14:53

#3 楼

是时候进行重写的时候了:

重写应用程序的成本+维护重写的应用程序的成本小于随时间推移维护当前系统的成本。

一些因素表明使得维护当前语言更加昂贵:


这种语言太老了,您必须付钱给那些知道很多钱来编程的人(COBOL)。
(不幸的是,根据经验),该系统的硬件体系结构太旧了,以至于他们不得不搜寻Ebay和COLLECT零件以将其添加到正在运行的机器上,因为它们不再制造了。这被称为“硬件生命支持”,并且价格昂贵,因为随着零件的稀缺,它们(可能)价格上涨,或者它们(绝对)最终会用光。
它变得如此复杂,以至于//Here be dragons.评论是遍及整个代码。
您不能编写任何其他项目并为公司增加新价值,因为您总是在修补这种丑陋的野兽。


评论


这正是促使我参与其中的重写的原因。代码太脆弱了,添加新功能的成本也很高,以至于不能重写就不再是一种选择。

–坦率的剪毛
2010-09-22 13:33

我在这里笑到第二点。

– Paul Nathan
2010-09-22 17:33

@Paul:当客户告诉我的时候我也这样做了,然后我发现他们很认真...而且我会收集要求以进行重写。那真是令人兴奋的一天。

–瑞安·海斯(Ryan Hayes)
2010-09-22 18:15

问题是您如何衡量成本。

–user1249
2011年4月2日在18:05

我喜欢这个回应,有趣而真实。我想在“少”之前加上“量化”。如此多次,提出索赔很容易,但重要的是要量化浪费的时间。

–徐凯文
2012年8月9日在0:42



#4 楼

如果您需要对项目的体系结构进行根本性的更改,那么也许是时候重新开始了。

即便如此,潜在的一大堆代码仍然值得在您的代码中重用。新项目。

请注意公平警告。当前项目将使用无数的实际工时来测试和完善其业务规则,这对于从头开始的项目而言并非如此。

我怀疑时间框架或直觉是这种严厉措施的适当措施。您必须有清楚,明确和易于理解的理由参与此行动过程。

评论


您需要非常小心“重新使用大量代码”,这可能导致未使用的旧代码和不良的代码结构。我认为重构是更好的解决方案。

–mrwooster
2011年1月14日13:49

同意该语句的一部分应解释为“重构”到“新”项目中。也就是说,如果您确实已经在那条艰难的道路上做出了承诺。正如其他人所提到的那样,这是极为罕见的,几乎不应该这样做。

–丹·麦格拉思(Dan McGrath)
2011年1月14日13:57

+1。同样,重写将花费时间,在此期间必须进行维护,但是将需要在两个代码库上进行相同的更改。

–拉里·科尔曼(Larry Coleman)
2011年1月14日下午14:12

#5 楼

停止!重写几乎永远不是答案。重构通常是更好的选择。


当然,有时候重写是合理的:


切换到不存在迁移工具(或写得不够便宜的新平台)的情况。
要重写的应用程序微不足道。
原始应用程序的源代码丢失,恢复比重写更昂贵。
现有应用程序封装的绝大多数业务规则不再适用。
现有代码的活跃用户很少。
您拥有资源(时间,人才和工具)进行重写。出于法律或实际原因,现有应用程序无法在生产环境中运行。

要理解为什么我建议重构而不是重构,请考虑一下涉及重写。您必须:


了解现有应用程序的细微差别。当您考虑到它封装的所有微妙的业务规则,运行它的环境(包括人工和技术环境)以及当前解决方案的优缺点时,这通常并不是一件容易的事。通常,此信息存在的唯一位置(如果有的话)在现有应用程序的源代码中。不幸的是,执行重写的主要原因之一是现有代码难以理解和维护。
在经过测试且可靠的新应用程序中重现此功能(或其更新版本)。开发人员可能无法理解现有的代码,但是其用户通常会很好地理解。它可能无法满足他们当前的业务需求,但他们至少可以告诉您该应用程序在各种情况下的功能。

重构的最大优点是:


您可以一次取一小块东西。
任何更改都可以在现有的工作应用程序的上下文中进行测试。
通过进行小的更改并观察发生的情况,可以测试有关现有代码工作方式的假设。分阶段进行,而不是一次完成。基础(与必须完成重写才能为用户或开发人员带来任何好处的相对)。

还请记住,如果进行重写,则一定会引入很多新的错误,并且陷入新的代码库。

评论


您能否通过解释为什么重构多于重写好于扩展这个答案?何时才是重写的答案?

–加布林
2011年1月14日14:03

鉴于最常见的重写是在另一套衣服中只是一团糟,所以您是对的。如果您可以消除单个问题,那么您错了。合适的人这样做是没有绝对的。

– JensG
13-10-8在19:09

#6 楼

尽管我确实同意Kramii的回答和Joel的观点,但有时还是应该重写一下。在寿命长的应用程序(我说的是10-20年或更长时间)中,维护随着时间的推移变得越来越昂贵。这是因为随着快速维护补丁而牺牲了原始体系结构,代码变得越来越意大利式。而且,用于较老技术的开发人员变得越来越稀有,也变得更加昂贵。最后,硬件开始老化,找到新硬件,操作系统,框架等以在其之上运行旧应用程序变得越来越难。此外,随着业务的发展,较旧的系统很可能无法满足组织的业务需求,而全新的系统也可能无法满足组织的业务需求。以及新系统对企业的潜在利益,以及从头开始重写事物的成本。您对重写成本的估计非常悲观。它几乎总是比您想的要花更多的时间和更长的时间。

评论


+1代表霍夫施塔特定律。

–贝尔诺
2011年1月14日15:44

#7 楼

该图形可能会有所帮助,它是应用程序的代码库质量和业务价值的函数:



该图表伪装为重新设计何时遗留软件被证明是合理的,而在不合理的情况下则是合理的。例如,如果该软件具有很高的商业价值,并且代码质量很差,那么重新设计是合理的。

评论


您为什么要投资重写业务价值较低的项目?只是报废!

–Jørgen Fogh
16年6月7日在8:41

这就是为什么它指出“替换或...”的原因。您可以用有价值的东西代替。或者将其变成有价值的东西。但是你有一点。我将对其进行编辑以添加“ scrap it”选项。

–图兰斯·科尔多瓦(TulainsCórdova)
16年6月7日在10:45

#8 楼

我有一个与您的案例非常相似的案例,只是该代码甚至没有使用Struts。相反,我所做的是将目标定位为特别糟糕并造成很多问题的目标区域。这种有针对性的方法使我们越来越好。

在2年的时间里,我们与重构工作一起重构了点点滴滴。我们始终将“强化”任务纳入项目计划。通过专注于效果不好的特定领域,我们获得了最大的收益。有用的东西我们独自一人留下。同样重要的是,这项工作是在正常开发过程中完成的,并已发布。大量重写的问题是,您花费了一年或一年以上的时间,然后等到一切回来时,所有事情都发生了变化,一些令人讨厌的错误得到了解决,并且您失去了ROI。

我们从来没有重写整个事情。但是,我们确实停止使用该平台进行新工作,而是为一个大型新项目投入了新的新鲜平台。获得批准,我们在合理的时间内交付了出色的产品。

#9 楼

我曾在一家小型软件公司工作,该公司有几个DOS应用程序,这些应用程序已升级为可以处理Y2K,然后重写为Windows 16位应用程序,然后完全重写为具有附加“小”功能的32位应用程序(最终仅由一个客户)影响了整个结构。

一个人一个月就可以完成将16位代码移动到32位的操作,但是NOOOOOOOOO,我们不得不重写它以使Soooooooooo更好。这东西可能适合其他行业,甚至在开始之前就具有完整的规格和伪代码。规范已经创建,但是花了很长时间,甚至没有时间编写真实的代码。它发布晚了,比16位“开始”发布的bug多(它是在v.3.0上发布的,最终到了几乎一个星期都没有人报告新bug的程度)。

您认为重写3-4次相同的应用程序会带来一些改进,但是我只是认为GUI前端不能证明如此合理。

这是我的第一笔IT担任技术支持主管。我应该写一本关于如何不开发用于分发的软件的书。显然我们犯了很多错误,但是我们继续重写应用程序这一事实加剧了这种无能。

#10 楼

我认为我是职业生涯中唯一需要重写的地方:

公司合并,系统功能重叠很大。许多系统已被合并和淘汰,而其他系统仍在进行中。

我从仍然存在的另一家公司继承了一个系统。它具有庞大的代码库,曾经用来支持多个部门,这些部门与我们的部门非常相似,但是设计和框架却完全不同。仅剩一个商业部门在使用它,它赚了足够的钱,使这个东西在僵尸状态下还活着。所有旧的专业知识都消失了,没有文档。支持负担很高,每周都会失败。它尚未被合并到我们的公司系统中,因为我们公司从未支持过该特定业务领域,因此我们没有功能或专业知识。

这似乎是一种情况需要重写。看来我将不得不找出这个庞然大物,抽出专门用于这项业务的功能,并重写需要添加到我们现有系统中的部分。一旦做到这一点,我们现有的系统就可以支持这个新领域,而这头野兽可以摆脱困境。否则我会失去理智。

评论


听起来您的雇主需要与客户交谈并说明情况,以找出帮助客户的最佳方法,即使这意味着他们必须先支付更多的费用,因为从长远来看,他们可以节省开支。

–user1249
2011年4月2日在18:06



#11 楼

因此,在这里我坐在办公桌前,我开始为一个大的aspx文件(它背后的数据库)的绝对混乱重新编写代码,并替换了MsSQL的MS Access接口。

asp程序中满是



include(close.aspx)之类的东西,里面有一行代码可以关闭最后一个打开的数据库连接。
旧版代码只是随机注释掉了
不考虑安全性
意大利面条式代码,其中数千行。全部集中在一个文件中。
函数和变量的名称后面没有明确的含义

如果我们需要做一些细微的更改,就好像在噩梦模式下同时玩了5个kal-toh游戏。

我被聘用来复制功能,并制造出一种可定制和可销售的产品。问题在于,在过去的十年中,为满足每一项业务需求而写的东西(好吧,无论如何,我会说其中的五个或六个西格玛)。

如果我们不想要销售产品,他们可能不需要重写,因为它可以完成大多数想要的工作-也许不是很优雅,但是花钱在制作漂亮的代码上做同样的事并不明智。 '

#12 楼

Joel Spolsky在以下文章中有一篇非常出色的文章:
您不应该做的事情,第一部分

从您可以说出的标题来看,它是一个方面(他谈到了为什么永远不应该抛出代码的问题) )IMO,这是有很多道理的,我最近在Excel 25周年纪念日上观看了channel9的视频,其中一些开发人员说,即使在今天,如果您调查了源代码,仍然会检查修订并最终返回代码excel使用的是20年前写的。

您不确定100%(即使Netscape犯了错误(摘自Joels Article)),我也觉得Joel的文章是上帝寄给我的,因为我可能是悲观的,喜欢扔掉代码思维,我总是可以第二次写得更好,但是直到现在我才意识到这花了很多钱。

要给出一个具体的答案,我只想说您需要进行彻底的成本与价值分析。

我的真实世界:到目前为止,我正在开发v0.6的silverlight应用程序都有一堆异步调用,这些调用使代码如此复杂。自从本周发现Reactive Extensions以来,我真的很想重写大部分代码,但是现在我该如何告诉客户?该程序运行良好(有一些内存泄漏),但是他们不在乎吗?我不可能告诉他们哦,我要再花2-3周的时间,因为我想重新做些事情。但是,我要分支代码,然后在空闲时间重新编写/玩游戏。

我的2美分还可以!?

评论


您的第一个实现通常次优,因为在设计时有些事情您还不知道。这通常可以重构为形状,而不是重新开始,因为您很可能已经做对了。如果不是,则为概念证明,并且经常需要将其丢弃。

–user1249
2011年1月15日23:55

+1用于分支。很多人说“不要重写”,因为这似乎是在扔掉旧代码,但事实并非如此。您可以具有并行代码库。

–午餐
2014年4月7日,下午1:45

公平地说,如果您是向乔尔·斯波斯基(Joel Spolsky)寻求建议的人,那么您不应该完全重写:-)否则,只有在您可以说服所有利益相关者为何乔尔的论点不算在内时,才应该重写根据您的具体情况。

– gnasher729
15年5月31日在15:52

#13 楼

现有解决方案无法扩展。

我在找您,MS Access。

评论


我不确定您是否正在寻找合适的产品。 AFAIK并不意味着Jet Red可以扩展。

– JensG
13-10-8在19:11

这如何回答所提问题?

– gna
13-10-8在19:52

#14 楼

当重写允许组织采用能够提供竞争优势的策略或允许它以当前体系结构无法适应的某种方式更好地为其客户提供服务时,这就是答案。

相反,重写常常会减轻管理方面的麻烦:


所有内容都应在.NET中,
我们的开发人员说我们的代码很烂,
/>我们在技术上一直落后,
我们将找不到支持我们系统的资源,或者
已经过去十年了,所以现在该了。

这些担忧中的大多数都不会实现,如果能够解决,则可以解决。然而,最后一个是最糟糕的。本质上是:我们没有理由。

是的,就像汽车一样,系统将开始显示磨损迹象。这可以通过常规维修来缓解。您知道他们对预防性维护工作有多大帮助的看法。作为一项投资,例行维护(即重构和标准化)几乎总是比重写成本更低。

但是,我们必须预料到最终将需要重写。设定日期并为之暂定计划,但是随着日期越来越接近而倾向于实现其他战略目标,直到您有令人信服的理由,例如...

近年来,我们失去了机会赢得大量客户是因为我们无法及时或昂贵地满足他们的需求。我们的系统将使用可扩展的体系结构进行重写,该体系结构允许插入自定义项(并且不像我们当前所做的那样进行硬编码)。这将大大减少为有特殊需求的客户提供服务的时间和成本。我们将赢得更多客户,并更好地满足当前客户的需求。

评论


似乎您应该能够朝这个方向重构。重构时,您要记住创建所需的灵活性,以便易于编写下一个功能。

–伊恩
16年6月9日在15:00

#15 楼

永远不要重构-事实是如果代码是您编写的-您将无法做得更好。

除非您想更改技术,否则代码缺乏任何结构(i很久以前在某个PHP网站上看到它,作者只是复制/粘贴了spahgetti而不是include / class / function),或者您从另一个人手中接管了写得很差的东西。设计为黑匣子。模块化,简单的API,里面有什么……不那么重要:)如果您有意大利面,则可以将其关闭在黑盒中,这样就不会污染良好的代码。

评论


太棒了,Slawek! extremeprogramming.org/rules/refactor.html

–卢卡斯·埃德(Lukas Eder)
2011年1月14日在16:32

+1我喜欢您的意见,想知道您有关重写新API的想法吗? (请参阅下面的答案)

–基甸
2011-1-14在16:39



是的,这些都是好点。微软重写了winXP代码,他们甚至无法在第一个Vista零售版本中正确删除/复制文件。当他们只是在扩展其代码库时,我们一直在不断提高质量(W3.11 => W95 => W98 => ME => XP),而他们重写了许多核心部分的Vista却是一场灾难。对于新的API ...我将当前代码分开以保持原样,并在更高的层上使用新的API。例如。您的核心类保持不变,但集成使用新的API完成。除非一切都太混乱了,否则只能从0开始。

– Slawek
2011年1月14日在18:17

“……事实是,如果代码是您编写的,您将无法做得更好。”如果我有足够的代表,将否决这篇文章。这是最失败的,不现实的,并且意味着人们无法以某种方式前进到他们编写的代码是对过去编写的代码的改进。

–JᴀʏMᴇᴇ
13-10-9在12:51



@JᴀʏMᴇᴇ:同意-如果您在第一次实施时没有学到任何东西,也没有获得任何经验,和/或如果您确实有更多的知识/经验/见识,现在又不能做得更好,那么您可以;那你就是个土豆而不是程序员。

–布伦丹
18年2月3日,12:35

#16 楼

我认为,证明改写合理的主要原因是平台变更。例如,如果您有Windows桌面GUI应用程序,并且公司所有者决定他们希望下一个版本为基于Web的应用程序。尽管并非总是如此,但根据我的经验,除非原始开发人员编写了非常模块化和可重用的代码(几乎不会发生),否则在大多数情况下都需要重写。

#17 楼

根据Joel的说法,大笔改写是公司可能犯下的最严重的战略错误:

你不应该做的事情,第一部分...
要记住,当您从头开始时,绝对没有理由相信您会比第一次做得更好。首先,您可能甚至没有与版本1相同的编程团队,因此您实际上没有“更多经验”。您只是要再次犯下大多数旧错误,并引入一些原始版本中没有的新问题。

旧的咒语会被扔掉,当应用于大型时会很危险。规模化商业应用。如果您是实验性地编写代码,则当您想到更好的算法时,可能希望删除上周编写的功能。没关系。您可能需要重构一个类以使其更易于使用。也可以但是丢弃整个程序是一个危险的愚蠢行为,如果Netscape实际上有一些具有软件行业经验的成人监督,那么他们可能并不会因此受到如此严重的打击。


评论


是的我一直在寻找对此的反驳。有时必须这样做。

–琼
2010-09-22在12:51

没有引用Joel的文章,每个重写参数都是不完整的。我说的是,这篇文章有一些优点,但请您自己考虑。也许您应该说出为什么同意这篇文章。我个人不同意乔尔(Joel)的观点-仅仅是因为有时候,给自己挖一个新洞比让自己进一步陷入困境永远更好。无论如何,我认为重写将使那些潜在的业务流程浮出水面,以便进行重新评估。

–艾哈迈德
2010-09-23 5:34



Joels的文章很好,因为它仔细地解释了糟糕的事情会如何发展。

–user1249
2011年4月2日在18:08

Joel使用Netscape Navigator浏览器的示例。那是一种消费产品,正处于巨大的增长曲线中间,正与庞大的预算竞争。对于Netscape来说,这是一个战略性错误。另一方面,内部定制的“企业”软件项目是不同的。您不会急于争取市场份额。您的所有用户都不会选择竞争性产品,这没有任何危险。这取决于业务决策:从长远来看,重写的成本是否可以收回成本,或者是实现业务目标的最佳方法?

–斯科特·惠特洛克
2011年4月3日在20:59

我认为乔尔(Joel)触及了关键概念,即“您永远不知道尚未记录哪些决定,您必须学习艰难的方法”

–MathAttack
2012年10月23日,下午3:45

#18 楼

有一个经典的笑话,“如果我要去XI不会从这里开始”。

我曾经工作过一次,雇主的主要动机是要吸引人才,以延期早重写关键业务应用程序。我没有问的问题是,为什么您首先遇到这种情况?



原因应该是一个危险信号,


增加太多的功能来维持和逐步重构野兽的压力太大了,
该部门的能力太弱了,< br

从客户或管理部门获得很少的支持,以致无法进行增量工作,这会导致溃烂,直到问题达到无法忍受的程度。

因此,我同意乔尔的观点,即进行大规模重写可能是一个非常糟糕的主意-除非您有确凿的证据表明,看来需要进行大规模重写的所有潜在原因都已得到解决。 ,您很可能会在适当的时候重复该问题。

#19 楼

当需要使用一种全新的技术来提供所需的功能时。

“完全新”:如果您打算重写但使用相同的平台,那么重构和明智的重组几乎肯定会更好解。这里使用的“平台”有点含糊-考虑它包括语言,也许还包括OS(从Linux扩展到Windows或反之亦然),但可能没有框架(例如用Spring代替Struts)。

“需要提供所需的功能”:大约在2000年,我启动了一个项目,用C ++重写Java中的主要服务器组件,以实现即用型线程,对象缓存和客户控制的交易。当时,我们不得不支持多个C ++线程库,而启用线程的许多数据库代码将需要几乎全部重写。至于由客户控制的交易……旧的体系结构将不会发生。

即使那样,我也不敢确定自己会重写,除非我对最新版本有详细的了解。系统的行为,并且相对干净的代码在其11年的生命中并没有产生很多疣。

#20 楼

要确定重新开始的点,您需要确定当前项目继续执行的价值低于重新开始执行的价值。

之所以如此困难,是因为您可以准确估计团队在新项目上的发展速度,直到您真正开始它为止。就是说,如果使用对新项目的开发速度的非常保守的估计,该项目可以带来可观的投资回报,那么您就有重新开始业务的理由。

#21 楼

使用我的指标,您必须满足两个条件才能证明重写是正确的:


重写后,新功能将更容易/更快捷/更少的错误编写
少于或等于添加当前新功能所需的时间。

即使如此,您也希望限制重写的范围。例如,我们在一家公司中使用C ++编写了一些遗留软件,这些软件都是以不了解模块化的C程序员的思想为基础的。最终结果是跨越多个类和DLL的有限状态机形式的speghetti代码。我们有一个新要求,它与代码中内置的假设完全不同,并且将成为公司为客户提供专利的增值服务的一部分。

花了一些时间在代码上实现了功能方面,我非常清楚要弄清楚需要更改的几个switch语句中的哪一个,等等。我的建议是重写那段巨大的有限状态机代码—比扩展现有代码花的时间更少。我能够将以前是三个的DLL整合到一个DLL中,并提供了更多的面向对象的结构,这使得执行关键的新功能以及添加新功能变得更加容易。

还有其他三个使用该库的应用程序需要重写,因此我不想完全重写那些程序。范围仅限于库以及将库绑定到现有软件所必需的内容。我的估计还没有算下来,这项工作是值得的。重新设计后不久,我受命添加一个新功能。旧结构只用了我一个星期,而新结构只用了一天。

#22 楼

OP并没有指出项目的范围,但是我得到的主要线索是“使用旧的[libs]用旧的[语言/方言]编写”,对我来说,这是重写的主要驱动力。实际上,我从事过很多具有长寿的项目,最终都意识到,对编译器/解释器/操作系统进行适当的更新是维护代码库的重要任务。

简而言之,我将分阶段计划重写,首先在库中优先进行更新。也许可以在此过程中进行其他优化,但是您计划将某些更改推迟到以后的阶段,这可能是保持进度并避免卡住的好方法。

#23 楼

好吧,我可以想象一个假想的场景,在这个场景中,我可能会丢掉现有的代码库(假想的场景中,bucky球的重量和体积为零),当我们争相添加一些被忽略的功能和错误时,没人会在乎我们损失了几周还是几个月的生产力固定到系统中,并且该系统是如此微不足道,并且受到组织的憎恨,我可以在十分钟之内用notepad ++和一台上网本替换整个服务器和服务器,从而全面提高每个人的生产力和道德水平。)

对于几乎任何现实世界的场景,尽管我只建议就地进行重构。 ^ _ ^。当未记录的法律和业务要求开始出现,并且在最后一刻开始一起进行黑客入侵时,往往会有太多隐藏的,无法预料的成本来重写。

==进行重构,以获得更大的好处,并且东西==

使用常规的旧增量方法重构旧代码,



如果您有机会转换为UML并记录下有什么小小的过时的架构。

如果您使用的是版本控制,请研究生成一些代码搅动报告,并找出哪些文件和文件节更改最频繁。记下这些内容,因为它们可能是您首先要处理的领域。


在更改任何代码之前,请始终尝试添加一些测试范围(即使是丑陋的全栈功能测试也可以)。

如果处理大型的混乱程序代码提取逻辑,则打算更改为一些合理命名的方法或函数,并在可能的情况下添加一些测试用例来验证您的新方法。进行必要的修改,如果可能,请将更改参数化,例如页边距宽度或标题,这些更改通常会进行调整,以便下次进行更新会更直接。


使用适配器模式,避免在逻辑命名的类和方法的地毯下隐藏旧代码的繁琐代码,这样对于您和其他开发人员执行的大多数常见任务,您无需担心背后的可怕情况您的背后隐藏着一些漂亮的干净方法和类,您已经在其背后隐藏了旧版代码-像那些漂亮的家庭,他们在谷仓中保留了变形的杀手级僵尸前家庭成员,以便他们不会破坏日常的日常工作。农场 。 。 。一般。


随着您继续努力并清理代码部分,继续扩大测试范围。现在,您可以在需要/需要时以越来越高的信心深入挖掘并“重写”更多代码。

重复或应用其他重构方法来继续改进代码库。


通过抽象分支


在要删除的代码中定义问题点(持久层,pdf生成器,发票理货机制,小部件生成器等)。

针对针对此功能以及一般行为的代码库运行(如果需要,编写)一些功能测试用例(自动或手动,但您知道是自动的)。

将与该组件相关的逻辑从现有源库中提取到具有某些合理接口的类中。

现在验证所有代码是否正在使用新接口执行活动X,该活动以前是在整个代码中随机分散的(Grep代码库,向新类添加跟踪,并验证应该调用它的页面是等),您可以通过修改单个文件来控制将使用哪种实现。(对象注册表,工厂类,无论IActivityXClass = Settings.AcitivtyXImplementer();)

重新运行功能测试验证一切都正常的情况下,所有Activity X都被扔到新类中。

围绕新的活动X包装器类,尽可能编写单元测试。

实现一个新类,而该类比遵循与旧类相同接口的旧版实现要少一些意大利面条逻辑。

验证新类是否通过了为旧类编写的单元测试。

通过更改注册表/工厂方法/使用新类而不是其他方法来更新代码老阶级。

验证您的功能测试仍然通过。


开放式封闭原则和通用业务逻辑/持久层

在某种程度上,您可能可以摆脱展示,业务和持久性的束缚层并编写一个与旧解决方案完全向后兼容的新应用程序,或者至少仍可以处理旧解决方案输入的数据。我可能不会推荐这种方法,但是有时这是时间/时间表/资源/所需的新功能的合理折衷。


表示层至少应与业务和持久层分开。

实现一个新的ui和更好的表示层,该层使用相同的通用业务和持久层。

确认使用新ui创建的数据不会破坏旧ui。 (如果新工具的用户打断了旧工具的用户,您将陷入困境。)

如果要实现向后兼容,则应将所有内容保存在相同的持久层中。如果只想与新工具保持向前兼容性,则可以使用新数据库和新表或扩展表来跟踪旧系统中不存在的数据。


对于新功能和持久层,需要添加新表和方法,而不会更改现有的旧逻辑,也不会向现有表添加列,约束。

例如如果您需要开始跟踪雇主的紧急联系人,并且其他一些字段不修改现有的雇员表(我们不知道旧数据对该表的假设),则添加扩展表employee_ext id,employee_id,emergency_contact_id等。


将用户缓慢迁移到新系统上。如果可能的话,将旧系统设置为只读模式,或者只是添加一些警告信息,告诉用户X以后将不再可用。


在新的ui

扩展用户群。

继续清理其他重构方法的业务逻辑和持久层用户。



#24 楼

我要说的是,“重构与重写”空间中还有第三类...这正在更新您的语言版本,编译器和库...有时仅采用现代编码技术会带来很大的好处。

以C#为例,v7代码比v2编写的代码更加简洁,安全和简洁。.Elvis和null合并运算符之类的功能可以帮上大忙。切换编译器也可能使旧代码带来新的生命。因此,可能会使新的库更易于使用和实现的新库。网络是实现困难的一个很好的例子。

还嵌入式Linux系统...考虑安装新工具-从svn切换到git。或将Vi添加到您的系统等中。

不一定总是要进行重构还是重写。。您的体系结构可能需要改进,但是它可以工作……也许您只需要考虑一下代码的编写方式等。

#25 楼

我认为我从未见过有人重写旧版应用程序。

发生的事情是,人们正在编写具有不同架构,技术等功能的全新应用程序,这些功能与以前的应用程序具有某些共同点代。它被称为app 2.0,但实际上它与原始版本的共同点很少。

但这并不是对原始版本的“重写”,因为您正在尝试实现功能奇偶校验。