BIG何时重写答案?


278

刚读了有关“大改写”的问题,我就想起了一个我想自己回答的问题。

我有一个可怕的项目,传给我,是用Struts 1.0用旧Java编写的,表具有不一致的关系,或者根本没有关系,甚至没有主键的表也没有要用作主键的字段,但并不是唯一的。大部分应用程序都以某种方式“正常工作”。大多数页面被重用(复制粘贴的代码)并进行硬编码。曾经从事该项目的每个人都以一种或另一种形式诅咒它。

现在,我长期以来一直在考虑向高层管理人员建议对这个可怕的应用程序进行完全重写。我正在慢慢尝试个人时间,但我真的觉得这值得一些专门的资源来实现。阅读有关大型重写的文章后,我有了第二个想法。当我想说服上级支持我的重写时,这不是很好。(我在一家很小的公司工作,因此该提案有可能获得批准)

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



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

这是一个很好的问题。非常相关,这种情况在软件工程中经常发生。
布拉德·托马斯

Answers:


325

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

以下情况应引起您考虑某种重写。我将在此之后讨论如何决定要做什么。

  • 开发人员的准备时间非常长。如果要花更多的时间(根据经验水平)来提升新开发人员,那么就需要重新设计系统。所谓的加速时间,是指新开发者准备进行第一次提交之前的时间(基于一个小功能)
    • 大学毕业-1.5个月
    • 仍为绿色,但在-1个月前曾从事其他项目
    • 中级-2周
    • 经验丰富-1周
    • 高级-1天
  • 由于现有架构的复杂性,部署无法自动化
  • 由于现有代码的复杂性,即使是简单的错误修复也花费了太长时间
  • 新功能花费的时间太长,并且由于代码库的相互依赖性而导致成本过高(新功能无法隔离,因此会影响现有功能)
  • 由于现有代码库的相互依赖性,因此正式的测试周期会花费很长时间。
  • 在太少的屏幕上执行了太多用例。这会给用户和开发人员带来培训问题。
  • 当前系统所需要的技术
    • 具有技术经验的高质量开发人员很难找到
    • 已过时(无法升级以支持较新的平台/功能)
    • 仅有一种更具表现力的高级技术可用
    • 维护旧技术的基础架构的成本太高

这些事情是不言而喻的。何时决定是完全重写还是增量重建是比较主观的,因此更具政治性。我可以坚定地说的是,断然声明这绝不是一个好主意是错误的。

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

  • 技术
    • 组件之间的耦合是如此之高,以至于单个组件的更改无法与其他组件隔离。单个组件的重新设计不仅导致相邻组件的级联更改,而且间接导致所有组件的级联更改。
    • 技术栈是如此复杂,以至于未来的状态设计需要对多个基础架构进行更改。在完全重写中,这也是必需的,但如果在增量重新设计中需要它,则您将失去这一优势。
    • 无论如何,重新设计组件都会导致对该组件的完全重写,因为现有的设计是如此愚蠢,以至于没有什么值得保存的。同样,在这种情况下,您将失去优势。
  • 政治
    • 不能使发起人了解渐进式重新设计需要对该项目的长期承诺。不可避免地,大多数组织对渐进式重新设计所造成的持续的预算消耗失去胃口。这种食欲不振对于改写也是不可避免的,但是发起人将更倾向于继续,因为他们不想在一个部分完整的新系统和部分过时的旧系统之间分裂。
    • 系统的用户也非常依赖其“当前屏幕”。在这种情况下,您将没有许可证来改善系统的重要部分(前端)。重新设计可以使您避免此问题,因为它们是从新事物开始的。他们仍然坚持要获得“相同的屏幕”,但是您还有更多弹药可以退回。

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

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

成功的一些策略:

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

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

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

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

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

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

109

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

有几个陷阱:

  • 重写总是花费比预期更长的时间。
  • 重写对客户没有直接影响/好处。
  • 专门用于重写的容量不用于支持客户。
  • 除非您拥有100%的文档,否则您将通过重写失去功能。

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

在以下情况下,重写可能是答案:

  • 您正在切换到另一种语言或平台。
  • 您正在切换框架/外部组件。
  • 现有的代码库不再可维护。

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


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

当前用于演示应用程序(最近没有客户购买它,我认为现在是重新创建它的最佳时间)。
乔恩(Jonn)2010年

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

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

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

72

现在是时候进行重写了:

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

保持当前价格昂贵的一些因素:

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

这正是促使我参与其中的重写的原因。该代码是如此脆弱,增加新的功能的成本如此高,那不是重写不再是一个选项。
Frank Shearar 2010年

16
我在这里笑到第二点。
保罗·内森

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

3
问题是您如何衡量成本。

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

17

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

即使这样,潜在的一大堆代码仍然值得在新项目中重用。

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

我怀疑时间框架或直觉会否适合这种严厉措施。您必须有明确可辩护易于理解的理由参与此行动过程。


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

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

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

12

尽管我确实同意Kramii的回答和Joel的观点,但有时还是应该重写一下。在寿命长的应用程序中(我说的是10到20年或更久),随着时间的推移,维护变得越来越昂贵。这是因为随着快速维护补丁而牺牲了原始体系结构,代码变得越来越意大利式。而且,用于较老技术的开发人员变得越来越稀有,而且价格更高。最终,硬件开始老化,找到新的硬件,操作系统,框架等以在其之上运行旧应用程序变得越来越困难。而且,企业在发展,并且较旧的系统很可能无法满足组织的业务需求,而全新的系统则无法满足组织的业务需求。

因此,您必须权衡所有正在进行的维护成本以及新系统对企业的潜在利益,而不是从头开始重写事物的成本。是非常在你对一个重写的成本估算悲观。它几乎总是比您想像的要花费更多且花费更长的时间。



11

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


当然,也有时候改写是有道理的:

  • 您将切换到一个不存在迁移工具(或编写成本不够便宜)的新平台。
  • 要重写的应用程序很简单。
  • 原始应用程序的源代码丢失了,恢复要比重写昂贵。
  • 现有应用程序封装的绝大多数业务规则不再适用。
  • 现有代码的活跃用户很少。
  • 您有资源(时间,才能和工具)来进行重写。
  • 出于法律或实际原因,现有应用程序无法在生产环境中运行。

要了解为什么我建议重构后要重构,请考虑重写中涉及的内容。你必须:

  1. 了解现有应用程序的细微差别。当您考虑到它封装的所有微妙的业务规则,运行它的环境(包括人工和技术环境)以及当前解决方案的优缺点时,这通常并不是一件容易的事。通常,此信息存在的唯一位置(如果有的话)在现有应用程序的源代码中。不幸的是,执行重写的主要原因之一是现有代码难以理解和维护。

  2. 在经过测试且可靠的新应用程序中重现此功能(或其更新版本)。开发人员可能无法理解现有的代码,但其用户通常会很好地理解。它可能无法满足他们当前的业务需求,但是他们至少可以告诉您该应用程序在各种情况下的功能。

重构的最大优点是:

  • 您可以一次将一小块东西拿走。
  • 任何更改都可以在现有的有效应用程序的上下文中进行测试。
  • 可以通过进行少量更改并观察发生的情况来测试有关现有代码工作方式的假设。
  • 变更通常可以分阶段交付给用户,而不是一次全部交付给用户。
  • 从重构的早期阶段学习可以为重构的后期阶段提供信息。
  • 如果您从头开始放弃该过程,则在更清晰的代码库方面仍然会有好处(与必须完成重写才能为用户或开发人员带来好处的重写相反)。

还要记住,如果您进行重写,则一定会引入很多新的错误并弄乱新的代码库。


2
您能否通过解释为什么重构多于重写好于扩展这个答案?而当一个重写的答案?
gablin 2011年

鉴于事实是最经常的重写只是在另一套衣服上是一样的烂摊子,所以您是对的。如果您可以消除单个问题,那么您错了。合适的人这样做是没有绝对的。
JensG 2013年

10

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

在此处输入图片说明

该图表伪装成一个指南,说明什么时候可以对传统软件进行重新设计,什么时候不应该。例如,如果该软件具有较高的商业价值,并且代码质量较差,则需要进行重新设计。


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

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

8

我认为我是职业生涯中唯一需要大笔重写的情况:

公司合并,系统功能重叠很大。许多系统已经合并和淘汰,而其他系统仍在此过程中。

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

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


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

7

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

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

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

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


5

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

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

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


5

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

这个asp程序充满了诸如

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

如果我们需要进行一些微小的更改,就好像在噩梦模式下同时玩了五次kal-toh游戏一样。

我被聘用来复制功能,并制造出一种可定制的产品,并可以向行业中其他人推销。问题在于,在过去的十年中,已经写了这本书来满足每一个业务需求(无论如何,我会说其中约有五,六西格码)。

如果我们不想出售产品,那么他们可能就不需要重写,因为它可以满足他们的大部分需求-也许不是很优雅,但是花一些钱来编写漂亮的代码并不明智'做同样的事。'


4

乔尔·斯波斯基(Joel Spolsky)在这方面有出色的文章: 切勿做的事情,第一部分

从标题可以看出,它有点单面(他在谈论为什么不应该抛出代码)IMO,它有很多道理,我最近在Excel 25周年上看到了channel9视频,其中一些开发人员说,即使在今天,如果您查看源代码,也要检查修订版本并最终返回到20年前使用的excel代码。

您不能百分百确定(即使Netscape犯了错误(摘自Joels文章)),我也觉得Joel的文章是上帝寄给我的,因为我很悲观,喜欢扔掉代码,以为我总能再写一遍时间,但直到现在我才意识到这花费了很多

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

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

只需我的2美分即可!!


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

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

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

3

现有解决方案无法扩展。

我正在看您,MS Access。


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

这如何回答所提问题?
蚊蚋

3

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

你不应该做的事情,第一部分

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

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


5
是的 我一直在寻找对此的反驳。有时必须这样做。
乔恩(Jonn)2010年

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

Joels的文章很好,因为它仔细地解释了坏事如何发生。

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

我认为乔尔(Joel)达到了关键概念,即“您永远不知道尚未记录哪些决定,您将不得不学习艰难的方式”
MathAttack 2012年

2

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

除非您想更改技术,否则代码将缺少任何结构(我很久以前就在某个PHP网站上看到过该代码,作者只是复制/粘贴了spahgetti而不是include / class / function),或者您从另一个人那里接管了写得很差。

一切都应该设计成黑匣子。模块化,简单的API,里面有什么……不那么重要:)如果您有意大利面条,则可以将其关闭在黑盒中,这样就不会污染良好的代码。



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

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

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

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

2

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


2

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

我曾经工作过一次,雇主的主要动机是吸引人才到公司来进行早就应该重写的业务关键型应用程序。我没有问的问题是,为什么您首先遇到这种情况?无论原因是什么,都应该是一个危险信号

  • 增加功能以维持和逐步重构野兽的压力太大,

  • 部门能力太弱

  • 来自客户或管理层的买入很少,无法进行增量工作,

等等,这会导致溃烂,直到问题达到无法忍受的程度。

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


2

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

取而代之的是,重写常常可以减轻管理方面的麻烦:

  • 一切都应该在.NET中,
  • 我们的开发人员说我们的代码很烂,
  • 我们在技术上落后
  • 我们将无法找到资源来支持我们的系统,或者很多时候,
  • 已经十年了,是时候了。

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

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

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

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


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

1

当转向一种全新的技术时,需要提供所需的功能。

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

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

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


0

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

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


0

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

  1. 重写后,新功能将更容易/更快捷/更少的错误编写
  2. 与添加当前新功能相比,重写将花费更少或相等的时间。

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

在花了一些时间实现其他功能的代码之后,我非常清楚要花多长时间找出我需要更改的几个switch语句中的哪一个,依此类推。我的建议是重写以前的代码部分。巨大的有限状态机-比扩展现有代码花的时间更少。我能够将以前是三个的DLL整合到一个DLL中,并提供了更多的面向对象的结构,这使得执行关键的新功能以及添加新功能变得更加容易。

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


0

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

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


0

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

对于几乎所有现实情况,我都建议您进行适当的重构。^ _ ^。当未记录的法律和业务要求开始出现,并且在最后一刻开始将所有东西一起入侵时,往往会有太多隐藏的,无法预料的成本来重写。

==在原地进行重构以获取更大的利益,并且==

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

  1. 如果您有机会转换为UML并记录其中有什么小小的卡纳尔体系结构。
  2. 如果您使用的是版本控制,请查看生成一些代码变更报告并找出哪些文件和文件节更改最频繁。记下这些内容,因为它们可能是您首先要处理的领域。
  3. 在更改任何代码之前,请始终尝试添加一些测试范围(即使是丑陋的全栈功能测试也可以)。如果要处理大量混乱的程序代码提取逻辑,则打算更改为一些合理命名的方法或函数,并在可能的情况下添加一些测试用例来验证您的新方法。进行必要的修改,并在可能的情况下对更改进行参数化(如果该更改通常是经过调整的,例如边距宽度或标题),则下次进行更新会更加直接。
  4. 使用适配器模式,避免在逻辑命名的类和方法的地毯下隐藏旧代码的繁琐代码,因此对于大多数常见任务,您和其他开发人员执行的操作将无需担心后面会发生的可怕事情您的背后隐藏着一些漂亮的干净方法和类,您已经在其背后隐藏了旧版代码-像那些漂亮的家庭,他们在谷仓中保留了变形的杀手级僵尸前家庭成员,以使他们不会破坏日常的日常工作。农场 。。。一般。
  5. 随着您继续努力并清理代码部分,继续提高您的测试覆盖率。现在,您可以在需要/需要时以越来越高的信心深入挖掘并“重写”更多代码。
  6. 重复或应用其他重构方法来继续改进您的代码库。

通过抽象分支

  1. 在要删除的代码中定义问题点(持久层,pdf生成器,发票理货机制,小部件生成器等)。
  2. 针对以该功能和一般行为为目标的代码库运行(如果需要,编写)一些功能测试用例(自动或手动,但您知道是自动的)。
  3. 从现有源库中将与该组件相关的逻辑提取到具有某种合理接口的类中。
  4. 验证所有代码现在正在使用新接口执行活动X,该活动先前是在整个代码中随机分散的(Grep代码库,向新类添加跟踪并验证应该调用它的页面,等等),并且您可以通过修改单个文件来控制使用哪种实现。(对象注册表,工厂类,无论IActivityXClass = Settings.AcitivtyXImplementer();)
  5. 重新运行功能测试用例,以验证所有活动X都已投入新类,一切仍在正常运行。
  6. 围绕新的活动X包装器类编写单元测试。
  7. 与遵循与旧类相同接口的旧版实现相比,用更少的意大利面条逻辑实现新类。
  8. 验证新类是否通过了您为旧类编写的单元测试。
  9. 通过更改注册表/工厂方法/使用新类而不是旧类来更新代码。
  10. 验证您的功能测试仍然通过。

开放封闭原则和公共业务逻辑/持久层

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

  • 表示层至少应与业务和持久层分开。
  • 实现一个新的ui和更好的表示层,该层使用相同的通用业务和持久层。
  • 验证使用新ui创建的数据不会破坏旧ui。(如果新工具的用户打断了旧工具的用户,您将陷入困境)。如果您正在争取向后完全兼容,则应将所有内容保存到相同的持久层。如果只想与新工具保持向前兼容性,则使用新数据库和新表或扩展表来跟踪旧系统中不存在的数据。
  • 对于新功能和持久层,需要添加新表和方法,而不会更改现有的旧逻辑,也不会向现有表添加列和约束。例如,如果您需要开始跟踪雇主的紧急联系人,并且其他一些字段不修改现有的员工表(我们不知道旧数据对该表的假设),则添加扩展表employee_ext id,employee_id,emergency_contact_id等。
  • 将用户缓慢迁移到新系统上。如果可能的话,将旧版系统设为只读模式,或者添加一些警告提示用户,使其在X日之后将不再可用。
  • 在新用户界面中实现任何优先级缺失的功能或业务要求
  • 扩展用户群。
  • 继续清理用户其他重构方法的业务逻辑和持久层。

0

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

以C#为例,v7代码比v2编写的代码更加干净,安全和简洁。Elvis和null合并运算符之类的功能可以帮上大忙。

切换编译器也可能使旧代码带来新的生命。因此,新的库可能会使操作和实现变得更容易。...网络是实现困难的一个很好的例子。

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

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


-2

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

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

但是,就您要实现功能奇偶性而言,这实际上不是对原始版本的“重写”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.