Questions tagged «refactoring»

重构是一种用于重组现有代码主体,在不更改其外部行为的情况下更改其内部结构的有纪律的技术。

11
进行TDD的人们在进行大型重构时如何处理工作流失
一段时间以来,我一直在尝试学习为我的代码编写单元测试。 最初,我开始做真正的TDD,在这里我不会写任何代码,除非先编写一个失败的测试。 但是,最近我要解决一个棘手的问题,其中涉及很多代码。在花了几周时间编写测试然后编写代码之后,我得出了一个不幸的结论,即我的整个方法都行不通,我不得不花两周的时间重新开始。 刚编写代码时,这是一个非常糟糕的决定,但是当您还编写了数百个单元测试时,将其全部扔掉在情感上变得更加困难。 我不禁会认为我浪费了3到4天的时间来编写这些测试,因为我本可以将代码放在一起进行概念验证,然后在对方法满意后再编写测试。 练习TDD的人如何正确处理此类情况?在某些情况下是否存在违反规则的情况,或者即使该代码可能看起来毫无用处,您还是总是总是首先刻意编写测试吗?
37 tdd  refactoring 

10
消除魔术数字:什么时候该说“不”?
我们都知道,幻数(硬编码值)会对您的程序造成严重破坏,尤其是当需要修改没有注释的一段代码时,您会在哪里划清界线? 例如,如果您有一个计算两天之间的秒数的函数,您是否要替换 seconds = num_days * 24 * 60 * 60 与 seconds = num_days * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE 您在什么时候确定硬编码值意味着什么是完全显而易见的,而不管它呢?

12
编写代码方法论的逐渐转变是否会影响系统性能?我应该在乎吗?
TD; DR: 关于我在问的问题有些困惑,所以这是问题背后的驱动思想: 我一直希望这个问题是什么。我本来可能说得不太好。但是其意图一直是“ 模块化,分离,松散耦合,解耦,重构的代码 ”,其本质明显比“ 整体式单一单元,在一个地方完成所有工作,一个文件,紧密耦合的 ”代码慢。剩下的只是我当时或现在或以后会遇到的细节和各种表现形式。在某种程度上,它肯定较慢。就像无碎片磁盘一样,您必须从任何地方拾起碎片。慢一点 当然。但是我应该在乎吗? 问题不在于... 与微优化,过早优化等无关。这与“优化这一部分或死亡”无关。 之后怎么样了? 它涉及随着时间而出现的有关编写代码的总体方法,技术和思考方式: “将此代码作为依赖项注入到您的类中” “每个班级写一个文件” “将视图与数据库,控制器,域分开”。 不要编写意大利面同质的单个代码块,而是编写可以协同工作的许多单独的模块化组件 它是关于在十年内当前在大多数框架中看到和倡导的代码的方式和样式,这些框架是在大会上倡导的,并且是通过社区传播的。这是思维方式从“整体块”到“微服务”的转变。随之而来的是机器级别的性能和开销,以及一些程序员级别的开销。 原始问题如下: 在计算机科学领域,我注意到编程方面的思维方式发生了显着变化。我经常遇到这样的建议: 编写较小的函数式代码(这种方式更具可测试性和可维护性) 将现有代码重构为越来越小的代码块,直到大多数方法/函数只有几行长并且很清楚它们的目的是什么(与更大的整体块相比,它创建了更多函数) 编写只做一件事的函数-关注点分离等(通常会在堆栈上创建更多函数和更多帧) 创建更多文件(每个文件一个类,用于分解目的的更多类,用于诸如MVC,域架构,设计模式,OO等层的目的,这会创建更多文件系统调用) 与“旧”或“过时”或“意大利面条”编码实践相比,这是一个变化,在常规编码实践中,您的方法跨越2500行,并且大型类和上帝对象可以完成所有工作。 我的问题是这样的: 当涉及到机器代码,1和0,汇编指令以及HDD盘片时,我应该完全担心我的类完全分离的OO代码以及各种重构的小型函数和方法也会生成额外的开销? 细节 尽管我对ASM到底如何处理OO代码及其方法调用以及DB调用和编译器调用如何转换为在HDD磁盘上移动执行器臂的方式并不太熟悉,但我确实有一些想法。我假设每个额外的函数调用,对象调用或“ #include”调用(在某些语言中)都会生成一组额外的指令,从而增加代码量并增加各种“代码接线”开销,而无需添加实际的“有用”代码。我还认为可以在ASM实际上在硬件上运行之前对其进行良好的优化,但是优化也只能做很多事情。 因此,我的问题是-与“包含一个大方法,其中包含一个大方法一切都放在一个整体文件中”,由于这种开销? 为清楚起见,更新: 我假设采用相同的代码并将其拆分,重构,解耦为越来越多的函数,对象以及方法和类将导致越来越多的参数在较小的代码段之间传递。因为可以肯定的是,重构代码必须保持线程运行,并且这需要传递参数。与单个整体类或方法相比,更多的方法,更多的类或更多的Factory Method设计模式导致传递更多信息位的开销更大。 有人说(引用待定),所有代码中多达70%是由ASM的MOV指令组成的-向CPU寄存器加载适当的变量,而不是进行实际的计算。就我而言,您可以使用PUSH / POP指令来加载CPU时间,以提供各种代码之间的链接和参数传递。您编写的代码段越小,所需的“链接”开销就越大。我担心这种联系会增加软件的膨胀和减慢速度,我想知道我是否应该关注这一点,以及是否要关注(如果有的话),因为现在和将来的下一代程序员都在为下个世纪构建软件,则必须使用和使用使用这些做法构建的软件。 更新:多个文件 我现在正在编写新代码,正在逐渐替换旧代码。特别是我注意到旧的类之一是〜3000行文件(如前所述)。现在,它已成为位于各个目录中的15-20个文件的集合,包括测试文件,不包括我用来将某些东西绑定在一起的PHP框架。还有更多文件。对于磁盘I / O,加载多个文件比加载一个大文件要慢。当然,并非所有文件都已加载,它们是根据需要加载的,并且存在磁盘缓存和内存缓存选项,但我仍然相信,这loading multiple files需要比loading a single file内存更多的处理工作。我将其添加到我的关注中。 更新:依赖注入所有内容 过一会儿再说。我认为我的问题被误解了。也许我选择误解了一些答案。我并不是在谈论微优化,因为一些答案已经被挑出来了(至少我认为我所说的关于微优化的说法是用词不当),而是整体上“重构代码以放松紧密耦合”的动向。 ,在代码的每个级别。我是最近从Zend Con来的,这种风格的代码一直是公约的核心和核心内容之一。从视图中解耦逻辑,从模型中解脱视图,从数据库中解脱模型,并且如果可能的话,从数据库中解耦数据。依赖-注入所有内容,有时意味着只添加什么都不做的接线代码(函数,类,样板),但可以用作接缝/勾点,在大多数情况下,很容易使代码大小加倍。 …

4
这种重构的术语是什么
我敢肯定,以下的重构术语都有用,但是我不记得了,我的Google-fu让我失望了! 重构将if语句移动到将对其产生最大影响的位置,例如更改此位置 $test = someFunctionThatReturnsABool(); for($x = 0; $x < 10000; $x++) { if ($test) { echo $x; } } 对此 $test = someFunctionThatReturnsABool(); if ($test) { for($x = 0; $x < 10000; $x++) { echo $x; } }

7
我该如何防止意外地重复代码?
我在相当大的代码库上工作。数百个类,大量不同文件,许多功能,花费15分钟以上的时间才能提取新副本等。 如此庞大的代码库的一个大问题是,它具有相当多的实用程序方法,它们执行相同的操作,或者具有可能时不使用这些实用程序方法的代码。而且,实用程序方法不只是全部在一个类中(因为这将是一个巨大的混乱)。 我对代码库比较陌生,但是多年来致力于该代码工作的团队负责人似乎也遇到了同样的问题。这会导致很多代码和工作重复,因此,当发生问题时,通常会分成4个基本相同的代码副本 我们如何遏制这种模式?与大多数大型项目一样,并非所有代码都已记录在案(尽管有些文件已记录在案),并且并非所有代码都...很整洁。但是从根本上说,如果我们能够在这方面提高质量,那真是​​太好了,这样将来我们就可以减少代码重复,并且更容易发现实用程序之类的东西。 而且,实用程序函数通常在某个静态帮助器类中,在单个对象上工作的某些非静态帮助器类中,或者是主要“帮助”于其上的类的静态方法。 我进行了一个实验,将实用程序功能添加为扩展方法(我不需要该类的任何内部组件,并且肯定只在非常特定的情况下才需要)。这样可以防止主类杂乱无章,但除非您已经知道,否则实际上再也找不到了。

8
“变量应尽可能地处于最小范围内”是否包括“变量应尽可能不存在”的情况?
根据有关“ 原理变量比实例变量更喜欢局部变量? ” 的公认答案,变量应处于尽可能小的范围内。 将问题简化为我的解释,这意味着我们应该重构这种代码: public class Main { private A a; private B b; public ABResult getResult() { getA(); getB(); return ABFactory.mix(a, b); } private getA() { a = SomeFactory.getA(); } private getB() { b = SomeFactory.getB(); } } 变成这样的东西: public class Main { public ABResult getResult() { A …

10
如果可以使用后者,那么“父项x = new Child();”而不是“ Child x = new Child();”是一种不好的做法吗?
例如,我看过一些代码创建了这样的片段: Fragment myFragment=new MyFragment(); 它声明一个变量为Fragment而不是MyFragment,MyFragment是Fragment的子类。我对这行代码不满意,因为我认为该代码应为: MyFragment myFragment=new MyFragment(); 哪个更具体,是真的吗? 还是概括地说,使用以下做法是错误的做法: Parent x=new Child(); 代替 Child x=new Child(); 是否可以在没有编译错误的情况下将前一个更改为后一个?

9
何时重构
我已经阅读了Fowler的Refactoring一书中的大部分内容,并且在过去的大大小小中都重构了许多应用程序。 我发现很难教的一件事是“何时”重构。我倾向于基于过去对我非常有益的直觉。但是,在与人们讨论是应该立即保留一段代码还是现在重构代码时,很难忍受“胆量检查”。 我觉得应该有更严格的方法来解决这个问题,但是不确定它们是什么。 我了解“代码嗅觉”,红色-绿色重构和其他想法,但是我常常觉得,重构的最佳时间不是第一次编写代码,而是第二次或第三次使用代码并意识到这实际上是一个问题,正在实际使用中。

4
魔术字符串/数字的用法
这是一个颇具争议的话题,我想与程序员一样多。但是,为此,我想知道业务(或您的工作场所)中的常见做法。 在我的工作场所,我们有严格的编码准则。其中一部分专门用于魔术字符串/数字。它指出(对于C#): 除了定义符号常量外,请勿在代码中使用数字或字符串的文字值。使用以下模式定义常量: public class Whatever { public static readonly Color PapayaWhip = new Color(0xFFEFD5); public const int MaxNumberOfWheels = 18; } 有例外:几乎可以始终安全地使用值0、1和null。通常,值2和-1也可以。用于记录或跟踪的字符串不受此规则的限制。当文字的含义在上下文中很清楚且不受将来的更改时,允许使用文字。 mean = (a + b) / 2; // okay WaitMilliseconds(waitTimeInSeconds * 1000); // clear enough 理想的情况是在以下情况下一些官方研究论文对代码的可读性/可维护性产生影响: 魔术数字/字符串无处不在 魔术字符串/数字会被常量声明合理地替换(或在不同程度的覆盖范围内)-请不要因为使用“合理地”而对我大喊大叫,我知道每个人都有不同的想法,“合理地”是什么 魔术字符串/数字被多余地替换在不需要的地方(请参见下面的示例) 在与一位同事争论时,我希望这样做具有一些基于科学的论据,而后者将要声明常量,例如: private const char SemiColon = ';'; private …

11
哪些因素应该影响我如何确定何时与朋友一起放弃一个小项目?[关闭]
最近我发现自己处在困境中。现在已经与一个编程伙伴一起玩了将近8个月的游戏。我们都是从去年8月左右开始学习编程的新手,他是CS的二年级学生,我是一名IT贸易技术支持人员,并且是一位自学成才的程序员,拥有大量的书籍和在线订阅。 我一直看到的问题是,当我们写出一段代码时,它常常会被黑在一起,会有很多失败,如果这对我们中的一个人来说是一个全新的概念,那就是天真的解决方案。很好,我们正在学习,我希望我们的两个代码在第一遍或第二遍都被一起破解。当涉及到实际修复和重构那些被黑在一起的行为时,就会出现问题。 我的伴侣将坚持自己刚凑齐的行为,公然拒绝看到任何错误,因为它开始起作用。即使从结构上声称接近完美,即使它具有注释以及适当命名的方法和字段,我什至都无法尝试使用。无论我多么努力,我都无法让他看到明显的明显缺陷,这些缺陷将阻止行为的任何进一步更改或扩展,而又不会完全破坏行为,而与行为如此紧密耦合的所有事物也可能属于同一类。被黑客入侵的解决方案将永远保持被黑客入侵,深思熟虑的设计会像最初构思和测试时那样保持原样。 我花了很多时间来照顾新代码,就像我自己编写代码一样,我不知道该怎么做。我的伴侣今晚输了它,并明确表示,无论是什么,基准,常规做法,无可辩驳的证明,他的代码都将保持其最初的用法。即使已经写了整本关于您为什么要避免做某事的书,他也会拒绝承认其有效性,声称这只是别人的意见。 我对我们的项目有既得利益,但是我不确定是否可以继续与我的合作伙伴一起工作。我似乎有三个选择。 不再关心编译后的代码库功能,而只是尝试维护和解析几乎没有发展的行为。希望一旦事情开始严重破裂,他将看到并尝试做更多的事情,而不是仅仅对根本存在缺陷的设计施加创可贴。 继续对十年前其他能力更强的人提出的问题进行无休止的争论。 停止对该项目进行编程,放弃我的代码将近10,000行,并花费大量的时间进行设计工作,然后尝试自己寻找一个新项目。 我可以采取哪种方法来确定是否值得与这个人继续进行此项目?还是哪些因素会影响我的决定?我们已经编写了很多代码,除非有必要,否则我不想放弃。

6
您从处理技术债务中看到了什么收获?
关于技术债务的这篇文章有一些优点,包括: 当故事驱动时,处理“技术问题”最有效。代码库可能在任何地方都需要工作,但是由于面向用户的原因,只有在要处理代码的地方才能收到回报。如果没有故事要经过某个棘手的领域,那么在这方面的工作就会被浪费掉。 因此,我更喜欢像往常一样拍摄故事(但可能更少),并遵循“童子军规则”,使故事比您发现的更好。换句话说,无论故事指引到哪里,让我们编写更多测试,让我们更积极地重构。 这种方法至少具有以下优点: 保持“最明智”的故事流; 提供所有团队人才的帮助; 让整个团队学习如何保持代码干净; 将改进的重点放在需要的地方; 不会浪费“可能”需要的改进; 我已经看到代码质量对长期生产力有很大的影响,所以我相信应该处理技术债务。我认为上面的帖子很有道理,但是我对最后两点不太确定。我有兴趣了解清除技术债务带来的收益的真实经验,即使这与用户故事无关。 通过清理代码库和消除技术债务,您看到了哪些积极的好处?您使用什么方法来完成工作?

8
重构时如何保持单元测试正常工作?
在另一个问题中,揭示了TDD的难题之一是在重构期间和重构之后使测试套件与代码库保持同步。 现在,我非常喜欢重构。我不会放弃做TDD。但是我也遇到过这样的测试问题,即以较小的重构会导致很多测试失败。 重构时如何避免破坏测试? 您是否将测试写得更好?如果是这样,您应该寻找什么? 您是否避免某些类型的重构? 有测试重构工具吗? 编辑:我写了一个新问题,问我要问什么(但将此问题保留为一个有趣的变体)。

6
是否有一种设计模式可以消除检查标志的需要?
我将在数据库中保存一些字符串有效负载。我有两个全局配置: 加密 压缩 可以使用配置启用或禁用这些功能,方法是仅启用其中一个,两个都启用或两个都禁用。 我当前的实现是这样的: if (encryptionEnable && !compressEnable) { encrypt(data); } else if (!encryptionEnable && compressEnable) { compress(data); } else if (encryptionEnable && compressEnable) { encrypt(compress(data)); } else { data; } 我在考虑装饰器模式。是正确的选择,还是有更好的选择?

6
重构转换语句,转换语句是否真正有用?
我正在阅读本文,并想知道,是否通过用Dictionary或Factory替换它们来摆脱所有switch语句,以便我的项目中根本没有switch语句。 有些东西加起来还不够。 问题是,switch语句是否有任何实际用途,还是我们继续将其替换为字典或工厂方法(当然,在使用工厂方法时,将最少使用switch语句来创建对象)使用工厂...但仅此而已)。

13
我可以在不改变外部行为的情况下将重构推进多远?
根据Martin Fowler的说法,代码重构是(强调我的): 重构是一种用于重组现有代码主体,在不更改其外部行为的情况下更改其内部结构的规范技术。它的核心是一系列小的行为保留转换。每个转换(称为“重构”)几乎没有,但是一系列转换可以产生显着的重组。由于每个重构都很小,因此出错的可能性较小。每次进行少量重构后,系统也可以保持完全正常工作,从而减少了系统在重组期间可能严重损坏的机会。 在这种情况下,什么是“外部行为”?例如,如果我应用move方法重构并将某个方法移动到其他类,则看起来我在更改外部行为,不是吗? 因此,我有兴趣弄清楚变更在什么时候停止成为重构并变成更多。“重构”一词可能会被误用于较大的更改:它是否有不同的词? 更新。关于接口的很多有趣的答案,但是不会通过方法重构来改变接口吗?

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.