你如何阻止你重构工作可怕的代码?

我有这个问题。 我无法阻止自己重构现有的代码,但在我看来(也许是客观地)devise不当或包含其他“代码气味”。 这会对我的即时生产力产生显着的负面影响。 但最终会是一个很大的维修福利。

如果你也遭受这种“痛苦”,你怎么克制自己? 或者至less可以pipe理重构,以避免为了长期维护而需要修改大量现有代码。

对我来说有效的是因为工作而被解雇。 :\

这就是说,我的基本问题是双重的:

  1. 我正在重构没有人要求我开发的代码。

  2. 我发现很难把testing放在原地,所以没有他们就做了。 自然,这就打破了一些东西。

我学到的是:

  1. 不要使用你不需要的代码,也没有人要求你去工作。 考虑到过去的后果,现在很容易记住这一点。

  2. 当你需要重构代码时,你应该开始工作,进行testing,但是不必自动化。

在阅读了太多的TDD的东西之后,我倾向于把自动化testing看作是唯一的一种testing。 实际上,即使是一堆Debug.Print语句也可以进行体面的testing,以确定function是否保持一致。

如果你必须重构,而你不能做自动化testing,那么你必须做一些testing,不pipe是打印文本还是UI脚本,或者其他什么。 任何有效的testing都比没有testing好。

答案是你不。 只是因为代码的作品并不意味着它将始终工作。 错误的代码是错误的代码。

我们重构使代码更易读,更容易维护,并确保可靠性。

只要你保持旧代码的逻辑,它应该仍然工作,再加上整体更好的代码的额外奖励。

我总是试图离开代码比我发现它更好。

而是根据“底线利益”来倾听你的“内心声音”。 如果这个代码经常被重用,那么重构它就可能是有意义的。 然而,我通常会试图忽视我对“代码味道”的讨厌,并且真正关注重构的利益/浪费比率。

我不会说我受苦受难,但是我听到你的兄弟!

我认为我们需要使代码保持在比离开时更好的状态。 所以你的追求是高尚的 我们称之为“重构”。

我假设我们都同意重构的好处,而且这取决于代码是多么必要的……对于问题的关键是…

我克制自己的一个方法是,我知道它已经成熟。 而且我知道如何解决它。 而不是完全克制自己,我只是一步,像“提取方法”。 稍后再进行下一轮的修正(如果您确定这是最后一步,也许我们应该称之为“第二次帮助”或“甜点”)。 然后粘上一个大的TODO,所以你可以再次find它。 并澄清还需要做什么。

感谢有趣的问题。 这让我怀疑我们是否需要一个“Refactorors Anonymous”小组,我们可以围坐在一起,分享我们的问题和战争故事。

我通常不抑制自己。 如果我在我正在处理的代码中发现一个坏块,我直接更正它。

我正在研究一个已经维护了大约10年的软件,至less要工作十年以上。 在这种情况下,代码味道留在代码中的时间越长,我的开发人员和我越会偶然发现它,并浪费时间来试图找出问题或发明解决方法。 这比现在做这项工作要花费更多的钱。

一个例外是需要数天重构的大型devise问题。 如果这些工作不以重大的方式阻碍我现在的项目,那么我将它添加到我们的维护待办事项列表中,以在不久的将来作为计划的任务进行重构。

最高评分的答案,促使你继续前进和重构对许多情况是好的,但也有点简单。 (我可能会对此发表评论,但没有特权这么做 – 我希望它也可以独立运作。)

如果你和一个多年来一直在开发的大型(遗留)系统一起工作,那么总是有太多的事情需要一次重构(除非你这些年来非常严格,我不相信)。 所以,你根本无法得到你想要的所有切线; 这是你必须接受的事实。 否则,当原始更改(错误修复或增强)可以在更短的时间内完成(testing和重构包括在内)时,总是需要花费几天时间清理所有内容。

所以,通常你必须在某处画一条线。 仅重构只涉及当前任务的代码,只有在不会花费大量时间的情况下

至于体系结构的大检修 – 在处理上述大型代码库时当然是无法避免的。 你必须select那些被认为是最关键的东西,并且在你的过程中任务和优先级高得足以使他们真正完成,即使这些更改本身并没有增加外部价值(即只对开发人员具有立竿见影的价值,代码更易于pipe理)。 (现在,如果是不可能的 – 如果决策者不够聪明,看到有必要利用这些改进的时间,那么你的代码基本上是长远的。)

如果你没有任何商业软件开发的限制,你的里程可能会有所不同。 ;)

顺便说一句,好的问题 – 我也发现自己经常想到在哪里画线。

Martin Fowler提出这个问题:

它的实质是应用一系列小的行为保存转换,每个转换“太小,不值得去做”。 然而,这些转变的累积效应是相当显着的。 通过小步骤完成它们,可以降低引入错误的风险。 您还可以避免在进行重组时使系统崩溃 – 这使您可以在较长的时间内逐渐重构系统。 – 马丁福勒

所以,当你一次更改大量的代码时,我不会真的称这是一个真正的重构。 更像是完全重写特定的代码段。 变化应该是渐进的,“几乎不值得去做”。 过了一段时间你会注意到它们的累积效应

我听说“遗留代码”的定义是没有自动化testing的代码。 如果你在没有testing的情况下编写代码,那么我会build议在进行重大更改之前编写testing。 如果你有testing的地方,你可以重构,而不用担心打破这个糟糕的代码,因为你有testing支持你,并确保一切都仍然有效。

我通常不会触及任何遗留代码,除非我被要求广泛地构build它。 如果代码非常糟糕,以至于在整个地方添加一个特性级联,那么您就有一个真正的理由来重新devise它。

另外,还有一个非常非常真实的风险,就是你会引入已经在传统混乱中修复的bug。 这会让你看起来不专业。

国际海事组织唯一的好办法就是在生产之外慢慢重构旧的代码。 然后,当你认为function是相同的时候,通过旧的解决的错误,并确保没有旧的错误再次出现。

把它推广到质量保证部门,并吹嘘给pipe理层,最好是用一些很酷的新function。 如果新代码执行速度更快,这是一个确定的卖点。

一般来说,您将遇到两个问题:完全缺乏时间,pipe理层推动重新分配时间。 如果这些都不是问题,那么认为自己很幸运。

编辑: 乔尔斯波斯基有最好的答案 ,我相信。

我同意,这很诱人,但是如果你把注意力放在这个上面,你可能不会做任何真正的工作!

两点build议:

  1. 标记代码,以便日后清理(使用TODO注释或类似的东西)
  2. 给臭虫追踪系统添加一个臭虫代码。 也许你可以花点时间来修理一组他们。

完全有效的问题。

我用它来发现自己开始自动重构代码,当我碰到它。 当我进行手术5分钟左右(检查事情等)时,我突然感觉到,我正在做的事情需要比我预期的更长的时间。 在这一点上我问自己,这个兔子洞是否值得努力? 说实话,有时候是这样,但是大部分时间不是这样,过了一段时间,你意识到你要重写整个系统,就在这时候!

这让我陷入了不断问自己的习惯: 我正在编写的代码是否能帮助我在合理的时间内完成这个任务? 我是否在这个重构的过程中“浪费”了公司的时间,而在优先级列表中有更高的优秀项目呢?

我看到程序员甚至没有意识到他们正在做这件事。 他们将连续数天工作,让代码处于一种他们觉得现在可以开始实现新function或执行错误修复的状态。 他们无法区分重构和花在分配的问题上的时间。

我所做的只是评论我后来想要做的事情,只要和现有的系统一起工作,不pipe它有多丑! 这使我可以减less更多的事情,并且通过我的清单来更快速地完成任务。 (我们不做TDD …)

一旦你find时间,回来重构。

“重构现有的代码有效” – 这显然是less数意见,但这是一个完全浪费时间。 你试图克制自己是件好事。

如果你认为代码太糟糕, 那么在重构代码之前 ,先find一个不重要的错误 。 然后为该错误添加一个自动化testing。 只有让自己重构。

重构工作代码“我已经离开代码更好了”的态度往往是程序员的狂妄自大 。 在许多情况下,你并不知道你更好地保留了代码,你只是相信你做的。 如果你甚至没有修复一个错误或添加function,为什么冒着错误的风险?

首先,你必须认识到并接受,糟糕的代码很重要的唯一原因是需要阅读和/或修改。 只需要阅读和/或修改,如果你正在寻找一个错误或添加function。 所以如果你修正了错误或者增强的话,只能触摸代码。 所以,如果你碰到一些大规模嵌套的if-then-else语句,或者一个错误命名的variables或方法,除非你需要真正理解或改变代码来完成你实际工作的任务。 如果你必须改变代码,那么重构它足以使代码易于理解,并且更容易做出更改,但是不能更改。

你是否习惯性地重构了别人编写的代码,或者你在六个月前处于不同types的“区域”时编写的代码? 如果你的答案是后者,那么你就不会为了谋生而画画或做雕塑了……你会因为闯入人家而被捕,在购买之后很长时间“完成”你的作品。

我是Doxygen的超级粉丝,让我坚持一个简单的:

 /** * Function to rule the world * @todo make this actually work */ 

然后,我告诉Doxygen根据我的意见生成待办事项列表。 这有助于确保闻起来像脚的function不会被遗忘。

我回顾甚至两个月前我做的东西,并说:“哎呀,我在想什么……我应该这样做……”,结果是从来没有真正从消费者那里得到消费品。

如果其他人的代码一直在重新考虑,请尝试自问,如果这样做实际上改善了代码。 如果你能够重新devise一个函数,那么很明显你理解函数..所以除非你重写了一些(更重要的)好处,否则在它之上打一个评论,然后再回来。

当你习惯了所有的代码,并且已经思考了如何使事情变得更连贯一些的话,那么就潜入其中吧。否则,你将会重新考虑你以前的重构(这是一个多年的恶性循环完美!)。

所以,除非它内联,否则用在所有的地方..尽量避免弄乱它,除非你真的需要。 稍后回来,一举击中你的TODO列表。这样做是你唯一的直接目标。

哇,如果你明白我的意思,你们中的很多人都是强奸犯。 我想CYA,如果你只是短期工作的代码库,那么不要麻烦重构。 但是如果你长期拥有这个代码,那就去做吧! 但是你必须使用unit testing来备份你的新代码,并且如果testing还不存在的话,你将会影响你遗留代码的unit testing。

当我遇到我不喜欢的东西时,我曾经重构过代码,但现在不再了。 我从经验中发现,这不值得。 有更好的东西,你可以花时间。

我不重构的主要原因是引入一个新的bug的风险。 旧代码越糟糕,你犯错的几率就越高。 例如,旧的代码可能有一个意想不到的副作用。 这可以被认为是一个编码错误,你会在你的重写中删除它。 但是,调用重写函数的代码可能依赖于这种副作用。

我工作了很多非常丑陋的遗留代码,这些代码大都没有注释,而且没有规范。 代码只是做了什么,没有人真的可以说为什么。 他们只是知道它似乎工作。 尽pipe可怕,但这个代码确实是工作的,所以最好不要pipe它。

也就是说,我认为不好的代码应该被重写。 我不认为程序员应该自己做这种事情。 它应该被视为一个项目,具有确定的范围,时间表,testing计划等,就像实现一个新的function。

下面的童子军规则适用于(坏)代码和devise:
离开露营地比你发现的清洁剂!

停止关心。

我的意思是,cmon,我们都是工程师,而工程师们都喜欢把绝对完美的代码发送出去。 我们将继续尝试。 我们不会为我们的工作感到高兴,除非我们知道我们所触及的一切都是TMAPCE。 此外,我们只知道这种方式好多了…

所以,不要一直试图重构一点点的唯一方法就是不关心你的工作。
(正如我注意到的那样,这确实发生在我身上一次,那是非常难过的…直到我搬到一个不同的工作。)

我优先考虑。

当我有一些可用的周期(公顷),

我通常尝试重新分解代码:

  • 对其他人的工作很敏感
  • 实际上需要进行处理 ,这意味着定期触摸它
  • 由于性能原因或文件原因,按照该顺序,这是不好的形状

重新分解增加价值的地方,我这样做。 试图将未来的新function与重新分解重叠,使得在引擎盖下更容易做到。

不触摸任何我们感觉触摸的理由?

  • 通常旧代码已经被强化为input/输出,尽pipe笨拙,它可以工作。
  • 如果没有损坏,不要这样做。
  • 应该总是有新的东西可以工作,而且编码是正确的。 随着时间的推移,旧的东西会随着时间的推移而重新考虑。

我只是想补充说,如果有问题的项目是由unit testing支持的,那么重构的风险就会小得多,而且生产力成本也会降低(因为你要知道你到底什么时候正在错误)。

仍然有成本/收益要做,但原则上我同意Longhorn,你不应该停止自己。

我试图在零碎的基础上重构。 也就是说,当我需要添加新的function时,我会以这样一种方式重构它,以便首先添加该function。 这使得重构一个更慢的过程,但它往往会使添加更改更容易。

在开始重构之前,您需要对其进行全面的unit testing ,而没有人喜欢编写unit testing:)

如果我正在从事一项任务,我不会让任何阻碍它的东西 – 这太容易让人失望了。 任何看起来像是需要工作的东西都可以,但也许不是马上就做 – 记下/添加到你的bug追踪器中。

我们在问题跟踪器中创build了一个问题(或者您可以使用便笺本)来修复该代码,然后忘记问题。

这让每个人都知道,有代码是不好的,可能会导致一些问题,但也让我继续工作,我目前的任务没有太多分心。

我有麻烦的臭臭的代码,但通常会推迟清理和重构,直到我必须实际进行更改,或者如果我有一些停机时间。

在此之前,我只会注意对意见进行更改的意见。

我读了老Remus叔叔Remus关于Tarbaby的故事 。 或者我从商店里拿出其中一个标有“你接触它,你拥有它”的标志。

过去我曾经患过这种疾病,而且我微观上pipe理着我“坏”的好习惯。

基本上,我做了以下几点:

  • 我在任何时候都有两个独立的源代码树实例。
  • 如果我有一个大规模的重构,这不是最重要的,我在第二个分支砍掉它。
  • 然后,我会继续在第一个分支工作,只是维持第二个分支,做一些testing,以便确保我没有损坏任何东西。
  • 一旦我有信心,我会检查一下,我可以在生产周期中放慢速度(也就是说,不要在里程碑之前检查!)。

老实说,那个“重大”的重构从来不会经常发生 – 通常如果我需要这样做,它已经被分配了。 尽pipe如此,我已经有几次这样做了,但它派上用场了。 理想的情况下,如果你可以做一个分支,只是不断整合变化。

对于较小的东西,我会经常把这些变化保留在我的“主”分支中,并在本地运行一段时间。 当我正在处理的任何事情都触及这些文件时,我会检查整个变化 – 我们的stream程当前在检入之前包括一个“伙伴检查”系统,所以通常情况下它会清除同行审查。

无论如何。 可能比你关心的更倾向于大脑转储,但希望它有帮助。

通常重构可以减less或消除分配实际工作的需要。 如果你正在修复一个bug,那么重构是个好地方 – 假设有testing。 通过对代码进行简单的重构,使其更清洁或更高效,从而在较小的程度上添加新function,然后您将看到该function已经存在,以及如何让用户启用它。

简短的回答是,除非有迫切的需求,否则不要重构那些可行的代码。 一个好的清单是:

  • 我是否会每天使用这个代码长时间工作,而且我是唯一一个将会这样做的人。
  • 代码太糟糕了,无法正确理解。 通常我发现自己刚刚患上了一个没有在这里发明的综合症(那个别人的完美解决scheme不是我怎么会这样做,所以我想再做一次,除了骄傲以外没有任何真正的收获)。
  • 该体系结构是否不能支持所述新的工作(function,错误修复等)。
  • 代码是如此乱伦,以至于改变一些小东西会产生后续错误的巨大连锁反应。

如果你对其中任何一个回答“是”,那么可能是重构的时候了。

真的很容易

我们修改的所有东西,我们必须提出一个由QA工程师理解和审查的书面testing计划。 不修改的东西大大简化了实际获得代码发布。 因此,除非因为某些其他原因而触摸了这段代码,否则任何types的重构几乎都是不可能的。

编辑:即使你的公司没有这样的政策, 只要记住,你需要testing你的变化 。 估计您需要testing更改的时间。

回答“什么是附加值?” 也有帮助。

当有人试图修复未被破坏的代码时,就会想到有关假设的古老谚语。 处理有许多用户的丑陋代码会影响很多人的工作效率,特别是如果某个修补程序在一个环境中工作,而在另一个环境中则不起作用 任何在Intranet网站上工作的人都知道如何将JScript转换成JavaScript可能会产生许多不可预见的副作用。

我也患有重构性疾病,我通过指导其他人维护的代码或我必须维护的其他人的代码来处理这个问题。 通过处理,我的意思是“每小时检查一次版本控制,看是否有人触摸我的代码,如果他们这样做,做一个即时的差异”。

Interesting Posts