你怎么处理恶劣的代码?

时间:2009-08-21 14:24:50

标签: refactoring

当你被分配到代码那里工作时,你会怎么做? 残暴和过时到几乎难以理解的程度?

例如:硬件接口代码,混合逻辑,AND用户界面代码,ALL在相同的功能中?

我们一直看到错误的代码,但你实际上对它做了什么?

  • 你试着重构吗?
  • 如果不是,请尝试将其设为OO?
  • 或者您是否尝试了解它,进行必要的更改并继续前进?

22 个答案:

答案 0 :(得分:28)

取决于我的几个因素:

  1. 我将来会维护此代码,还是一次性修复?
  2. 完全更换此系统需要多长时间?
  3. 此刻我有多忙?
  4. 理想情况下,我会重构我必须维护的所有不良代码,但实际情况是当天只有这么多小时。

答案 1 :(得分:10)

通常情况下,“它取决于”。

我倾向于问自己以下一些问题:

  • 是否有现有代码的单元测试?
  • 重构代码是否可以为我的项目带来风险?
  • 作者是否仍然可以澄清我对代码的任何疑问?
  • 我的雇主会考虑将现有的,正常运作的代码所花费的时间用于我的时间吗?

等等......

但假设我有能力这样做,重构是优先的,因为现在修复代码的前期成本可能会在维护和开发时间之后节省我很多时间和精力。

还有其他一些好处,包括你保持代码库越干净和维护得越好,其他开发人员就越有可能保持这种方式。实用程序员称之为Broken Window Theory

答案 2 :(得分:8)

开发人员有一种直觉,认为代码总是很丑陋,因为其他劣质开发人员。有时,代码很难看,因为问题空间很难看。丑陋不仅仅是丑陋 - 它有时是机构记忆。代码中的每一行丑陋都可能代表错误修复。所以在你全力以赴之前要仔细考虑。

基本上,我会说除非你真的需要,否则你不应该触摸这样的代码。如果您可以解决一个真正的错误,那么重构是合理的,如果您可以确定您保持相同数量的功能。但是为了重构而重构(例如,“使代码OO”)是我通常将其归类为经典新手错误。

答案 3 :(得分:7)

本书Working Effectively with Legacy Code讨论了您可以做的选项。通常,规则不是在必须(修复错误或添加功能)之前更改代码。本书描述了如何在无法添加测试时进行更改以及如何向复杂代码添加测试(这允许进行更多实质性更改)。

答案 4 :(得分:3)

你试图在严格的意义上重构它,在那里你不改变行为。

第一个目标通常是打破巨大的方法。

答案 5 :(得分:2)

将其发布到www.worsethanfailure.com !!!

答案 6 :(得分:2)

要问的第一个问题是:是否有用

如果答案是肯定的,那么仅仅放弃并重新开始将是一个巨大的障碍。该代码中可能有数千个工时来处理边缘情况和令人讨厌的错误。更糟糕的是,系统中可能还有其他模块依赖于当前不正确(但已知且可能已记录)的行为。如果不破坏,请不要乱用它。

如果您热衷于清理它,请首先编写当前行为的测试用例。当您遇到行为与规范不同的实例时,您必须决定是否接受该行为为“正确”,或者按照规范说它应该做什么。

只有在您编写了所有通过的测试用例后才开始重构。测试会告诉你你的努力是否破坏了什么。

答案 7 :(得分:2)

就像其他任何代码一样,当你离开它时,它会比你输入它时稍微好一点。你永远不会重写整个代码。如果这是由于某种原因所需的工作,那么你就可以为它开始一个项目(小或大)。

我假设我们在这里谈论大量代码。

并非每天都是工作中美好的一天,你知道:)

答案 8 :(得分:2)

如果不需要修改,我不会碰它。

如果可能的话,我首先编写自动化单元测试,尤其关注需要修改的区域。

如果无法进行自动单元测试,我会尽力记录手动单元测试。

我现在只是使用测试来记录“当前”行为。

如果可能的话,我总是保留一个代码和可执行环境的版本,以“原始”的方式运行(在我触摸它之前)所以我总是可以添加新的“行为文档”测试并更好地检测我可能导致的回归后面。

一旦我开始改变事物,我要非常小心,不要引入回归。我通过在开始编写代码之前不断重新运行(和添加新测试)到我编写的测试来实现这一点。

如果可能的话,如果没有业务需要修复它,我会留下错误。这些错误可能是某些用户的“功能”,并且可能具有不明确的副作用,这些副作用在代码重新部署到生产之前是不明确的。

就重构而言,我尽可能积极地做到这一点,但仅限于我需要改变的代码。我可以在我自己的代码中更积极地重构,这些代码永远不会被检入,只是为了提高我个人代码的可读性。通常很难正确测试仅出于可读性原因而进行的更改,因此出于安全原因,我通常不检查/部署这些更改,除非我可以自信地测试代码更改是否完全安全(这对于当您进行除可读性之外的任何其他操作所必需的更改时,会引入错误。

真的,这是一个风险管理问题。谨慎行事。用户不关心代码是否是恶劣的,他们只关心它变得更好而不会变得更糟。在这种情况下,您对漂亮代码的需求并不重要,请通过它。

答案 9 :(得分:2)

使用已编译的遗留应用程序作为业务需求文档,将其废弃并重新开始。 并花时间与用户分析,看看他们想要改变什么。

答案 10 :(得分:2)

考虑到你使用的一些形容词的强度,即恶劣的过时的难以理解的,我会把它包装好!

如果它处于这样的状态,就像你给出的例子一样,它可能也没有得到任何测试代码。在许多其他答案中提到了重构,但有时候,这是不合适的。我总是发现,在重构时,你通常需要一条清晰的路径,通过这条路径可以将旧代码逐步转换为新的代码。

当旧代码远离您希望的外观时,例如您似乎建议的极端情况,您可能会在比预期更短的时间内重新设计,重写和测试新代码重构它。

答案 11 :(得分:1)

我会和我的经理谈谈并描述代码。大多数管理人员不希望通过绑扎线和胶带本身将程序结合在一起。如果代码确实那么糟糕,肯定会出现一些业务逻辑错误,硬编码等等,最终会破坏生产力。

我之前遇到过一些非常糟糕的代码(单个字母变量名称,没有评论,所有内容都挤在一行等等)。一旦我提到/向我的经理展示它们,他们几乎总是说“继续“写它”,因为你不仅要阅读和更改代码,而且未来的同事将不得不经历同样的痛苦。更好的是你只需要花一段时间来重写它,而不是让每个接触过代码的人都必须首先理解并解读它。

答案 12 :(得分:1)

有句老话。如果没有破坏,请不要修理它。如果你必须对它进行维护,然后对其进行反向工程并对其进行记录,以便下次遇到它时你会知道它的作用。

您不知道开发人员编写代码时的情况。写作时,他或她可能会遇到时间紧迫(管理层遍布开发人员等)

在某些情况下,他或她根据规范编写代码,然后规范发生了多次更改,开发人员必须修补代码,因为时间限制,重写是不可能的。这种情况一直都在发生。

如果代码影响应用程序的健壮性并且是模块化的,那么您可以重新考虑因素或重新编写代码。记录情况,以帮助未来的程序员理解。

许多程序员也考虑将其他开发人员代码进行逆向工程。 他们宁愿改写而不考虑这样做的后果。

如果您从未这样做过,请尝试一下,它会让您成为更好的开发者。

由于

答案 13 :(得分:1)

用火杀死它。

答案 14 :(得分:0)

真正AWFUL代码中最糟糕的犯罪者(根据我的经验)是人们可以轻松完成切割和切换。粘贴这些天。剪切&粘贴应该很少使用。如果您认为这是正确的解决方案,通常最好退一步并稍微概括一下问题。

答案 15 :(得分:0)

我的公司我们总是Refactor Mercilessly。所以我们仍然遇到了残暴的代码,但是很少而且越来越少......

我们编写了很多内部代码,该公司由同一家族运营约100年。管理层通常告诉我们,我们必须将代码库(evolve)维持50年左右。在这个设置中,你不敢触摸的代码被认为是公司长期生存的更大风险,然后是停机的前景,因为一些经过严格测试的代码因重构而破裂。

答案 16 :(得分:0)

只要您看到“几乎无法理解”的代码,请谨慎使用。您需要假设任何重大的重新分解都会导致引入新的错误,您需要找到并纠正错误。

此外,我已经多次看到这种情况(甚至自己曾经一次或两次成为受害者):程序员继承了遗留代码,决定代码是古老的&不可维护并决定重构它,最终删除多年来巧妙修补的关键“修复”或“业务规则”,最终花费大量时间追踪并重新引入类似代码,当用户抱怨“问题固定年份以前再次发生“。

重新分解(和调试)几乎总是花费比预期更长的时间,永远不应被视为与你应该做的任何任务一起出现的“免费赠品”。

“如果没有破产,不要'修复'它”仍然有很多道理。

答案 17 :(得分:0)

我在所有遗留代码上运行了复制粘贴检测器和findbugs。

然后我计划了我的初步重构:

  1. 删除未使用的代码,未使用的变量和未使用的方法
  2. 重构重复代码
  3. 设置一步构建
  4. 构建基本功能测试
  5. 到那时,代码符合可维护性的基本最小值。它可以很容易地构建,并且可以通过自动化测试找到基本错误。

    我经常添加这样的代码:

    log.debug("is foo null? " + (foo == null));
    
    log.debug("is discount < raw price ? " + (foo.getDiscount() < foo.getRawPrice()));
    

    当我可以重构它时,有些代码将被恢复用于单元测试。

答案 18 :(得分:0)

我已经在我们运送那种代码的地方工作了。

答案 19 :(得分:0)

我试着理解它,做出必要的改变,继续前进。

当然,理解它通常会涉及一些变化;至少,我在空白处移动并在同一列中排列相应的大括号,如下所示:

if(condition){
doSomething(); }

// becomes...

if(condition)
{
    doSomething();
}

我还经常更改变量名称。

很多时候,“必要的变化”需要重构。 :)

答案 20 :(得分:0)

取决于您的时间范围以及该代码对您的重要程度。如果你必须“只是让它工作”然后这样做并在时间允许时重写模块。

如果它是你所做的重要或不可或缺的一部分,那么重构重构重构。

然后找到写这篇文章的男/女并给他们发一张粗鲁的明信片!

答案 21 :(得分:0)

了解他们正在做什么以及完成的截止日期。一个更大的截止日期,通常从头开始重建大部分代码,因为我发现这是一个非常有价值的经验,不仅可以破译可怕的代码并使其清晰易读,而且在大脑的某个地方,这些神经元被压缩以避免类似的错误。未来。