几周前,我与一些同事就重构进行了讨论,我似乎属于少数人,他们认为“尽早重构,经常重构”是一种防止代码变得混乱和不可维护的好方法。许多其他人认为它只属于项目的维护阶段。
如果你有意见,请捍卫它。
几周前,我与一些同事就重构进行了讨论,我似乎属于少数人,他们认为“尽早重构,经常重构”是一种防止代码变得混乱和不可维护的好方法。许多其他人认为它只属于项目的维护阶段。
如果你有意见,请捍卫它。
就像你说的:早重构,经常重构。
尽早重构意味着必要的更改仍然在我脑海中浮现。重构通常意味着更改往往更小。
延迟重构只会导致一团糟,这进一步使重构变得更加困难。一旦我注意到乱七八糟的东西就立即清理可以防止它堆积起来并在以后成为问题。
我会尽快重构代码(所有测试都通过)。通过这种方式,我可以在它还记忆犹新的时候清理它,并且在其他人看到第一个版本有多丑之前。
在初次签入后,我通常会在每次接触一段代码时进行重构。重构不是你应该单独留出时间的事情。这应该是你边走边做的事情。
您戴着两顶帽子编写代码。刚刚得到的东西工作的帽子和我需要理解这个明天的帽子。显然,第二顶帽子是重构帽子。因此,每当您完成某些工作但(不可避免地)引入了重复代码、长方法、脆弱的错误处理、错误的变量名等气味时,您都会进行重构......
在尝试使某些东西正常工作时进行重构(即戴上两顶帽子)对于重要的任务是不切实际的。但是将重构推迟到下一天/下一周/下一次迭代是非常糟糕的,因为问题的背景会从你的脑海中消失。因此,尽可能频繁地在帽子之间切换,但不要将它们组合在一起。
我会重构我得到的每一个机会,因为它可以让我把我的代码磨练成最好的。即使在积极开发以防止首先创建不可维护的代码时,我也会这样做。它还经常让我在一个糟糕的设计决策变得无法修复之前纠正它。
重构的三个好理由:
不重构的三个充分理由:
“凌乱”是有争议的——有一个有效的论点被称为“修复破碎的窗户”或“代码卫生”,这表明如果你让小东西滑动,那么你也会开始让大东西滑动。这很好,记住这是一件好事,但请记住这是一个类比。它不能原谅无休止地分流东西,以寻找最干净的解决方案。
你重构的频率应该取决于好的原因出现的频率,以及你对测试过程保护你免于引入错误的信心。
重构本身从来都不是目标。但是,如果某些东西不起作用,则必须对其进行修复,这在初始开发和维护中都是如此。对于重要的更改,几乎总是重构并干净地合并新概念,而不是用大量垃圾修补一个地方以避免其他地方的任何更改。
对于它的价值,只要我掌握了接口的用途,并且由此产生的更改的范围是可管理的,我认为更改接口并不重要。
正如书中所说,你在什么时候重构
我试着遵循这个座右铭:让你接触到的所有代码都比以前更好。
当我进行修复或添加功能时,我通常会利用这个机会对受影响的代码进行有限的重构。通常这可以更容易地进行我的预期更改,因此它实际上不需要任何成本。
否则,您应该为重构安排专门的时间,如果因为您总是在灭火(我想知道为什么)而无法做到,那么当您发现进行更改变得比应有的困难得多并且“代码有异味”时,您应该强迫自己进行重构简直无法忍受。
很多时候,当我刷新想法时,我的代码开始时非常紧密耦合和混乱。当我开始完善这个想法时,逻辑分离开始变得越来越清晰,我开始重构。这是一个持续的过程,正如每个人都建议的那样,应该“尽早并经常”完成。
我在以下情况下进行重构:
我正在修改代码,我对此感到困惑。如果我需要一段时间才能筛选出来,它需要重构。
我正在创建新代码,并且在我让它“工作”之后。很多时候我会让事情正常工作,当我编码时,我意识到“嘿,我需要重做我所做的 20 行,只需进行一些更改”。那时我重构并继续。
在我看来,唯一应该阻止你这样做的是时间限制。不管你喜不喜欢,有时候你只是没有时间去做。
就像国家公园——总是让它比你发现它好一点。
对我来说,这意味着任何时候我打开代码,并且不得不挠头弄清楚发生了什么,我都应该重构一些东西。我的主要目标是提高可读性和理解性。通常它只是为了清楚起见重命名一个变量。有时它是提取方法 -
例如(琐碎),如果我遇到
temp = array[i];
array[i] = array[j];
array[j] = temp;
我可能会用 swap(i,j) 方法替换它。
编译器无论如何都会内联它,并且 swap() 从语义上告诉每个人发生了什么。
话虽如此,使用我自己的代码(从头开始),我倾向于为设计进行重构。我经常发现在具体课程中工作更容易。完成并调试后,我将使用旧的提取接口技巧。
我将把它留给同事进行重构以提高可读性,因为我离代码太近而无法注意到这些漏洞。毕竟,我知道我的意思。
机会主义地重构!只要容易就去做。
如果重构很困难,那么您是在错误的时间(当代码不需要它时)或在代码的错误部分(在其他地方可以获得更好的效率)进行重构。(或者你还不太擅长重构。)
为“维护”保存重构是一种重言式。重构就是维护。
每次阅读任何内容时我都会进行重构,使其更具可读性。不是重大重组。但是,如果我对自己说“这List
包含什么?哦,Integer
s!” 然后我将其更改为List<Integer>
. 另外,我经常在IDE中提取方法来放几行代码的好名字。
答案总是,但更具体地说:
每次遇到需要。至少当您要更改需要重构的一段代码时。
我将重构本地化为与我当前任务相关的代码。我尝试预先进行重构。我单独提交这些更改,因为从功能的角度来看,它与实际任务无关。这样代码更干净,修订历史也更干净。
“尽早重构,经常重构”是一个富有成效的指导方针。虽然那种假设你真的知道代码。系统越老,重构就越危险,需要更多的考虑。在某些情况下,重构需要管理任务、工作量和时间估计等。
不断地,在合理的范围内。您应该始终寻找改进软件的方法,但您必须小心避免为了重构而重构的情况(Refactorbation)。
如果您可以证明重构将使一段代码更快、更易于阅读、更易于维护或更容易或为业务提供一些其他价值,我说去吧!
如果您有一个可以安全地进行更改的重构工具,那么您应该在代码编译时进行重构,如果它会使代码更清晰。
如果您没有这样的工具,您应该在测试为绿色时进行重构,如果它会使代码更清晰。
做些小改动——重命名一个方法,让它的作用更清晰。提取一个类,使一组相关变量明确相关。重构不是要进行大的更改,而是要让事情分分钟变得更干净。重构是在每顿饭后清理你的盘子,而不是等到每个表面都被脏盘子覆盖。
绝对只要它看起来权宜之计。如果你不这样做,痛苦就会增加。
自从切换到 Squeak(我现在似乎在每篇文章中都提到)后,我意识到在原型设计期间的许多设计问题都消失了,因为在那种环境下重构真的很容易。老实说,如果你没有一个重构基本上是无痛的环境,我建议你尝试 squeak 只是为了知道它会是什么样子。
经常重构通常可以节省时间,或者至少可以节省一些时间。我正在做一个项目,我们在达到某个里程碑后重构了所有代码。这是一个很好的方法,因为如果我们需要删除不再有用的代码,它可以更容易地修补我们需要的任何新东西。
我们现在正在讨论这个问题。我们或多或少同意“写它让它工作,然后修复它”。但我们在时间角度上存在分歧。我更“立即修复它”,我的同事更“在下一次迭代中修复它”。
一些支持他的引用:
雅虎高级 Javascript 架构师 Douglas Crockford:
每 7 个 sprint 重构一次。
肯汤普森(unix 人):
代码本身几乎腐烂,它会被重写。即使什么都没有改变,由于某种原因它也会腐烂。
我希望一旦完成了提交的代码的任务,您可以在 2 个月内返回并认为“是的,我在这里做得很好”。我不相信以后找时间回来修复它是不容易的。从我的角度来看,相信这有点幼稚。
编辑:拼写错误
我认为当你目前正在处理它的一部分时,你应该重构一些东西。意味着如果您必须增强功能 A,那么您应该在之前(和之后?)重构它。如果您不使用此功能做任何事情,那么只要您有其他事情要做,就让它保持原样。
不要重构系统的工作部分,除非你已经不得不改变它。
关于这个主题有很多观点,其中一些与特定的方法或开发方法有关。使用 TDD 时,尽早进行重构,正如您所说,重构通常是一种受欢迎的方法。
在其他情况下,您可以根据需要进行重构。例如,当您发现重复代码时。
当采用更传统的方法进行详细的前期设计时,重构的频率可能会降低。但是,我建议不要在项目结束之前进行重构。您不仅可能会引入问题,可能是 UAT 之后的问题,而且重构通常也会变得越来越困难。出于这个原因,经典项目的时间限制导致重构和额外的测试被放弃,当维护开始时,你可能已经创建了一个意大利面条代码怪物。
如果它没有损坏,请不要重构它。
我想说重构的时间属于初始编码阶段,您可以随意多次进行重构。一旦它在客户手中,那么它就变成了另一回事。您不想为自己“整理”代码而发现它被运送并破坏了某些东西。
初始交付后重构的时间就是你说你会做的时候。当代码变得有点太臭了,然后有一个包含重构的专用版本,可能还有一些更重要的修复。这样,如果你碰巧弄坏了东西,你知道哪里出了问题,你可以更容易地修复它。如果你一直在重构,你会破坏一些东西,直到它得到 QAd 你才会知道它已经坏了,然后你将很难弄清楚是错误修复/功能代码更改导致了问题,还是某些问题您在很久以前进行的重构。
当代码看起来与以前大致相同时,检查 cbreak 更改会容易得多。重构很多代码结构,你可以让它几乎不可能,所以只有在你认真的时候才重构。像对待任何其他产品代码更改一样对待它,你应该没问题。
我认为这篇 Top 100 Wordpress 博客文章可能有一些很好的建议。 http://blog.accurev.com/2008/09/17/dr-strangecode-or-how-i-learned-to-stop-worrying-and-love-old-code/