Questions tagged «refactoring»

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

17
如何使重构成为我团队的优先事项?
我每天使用的代码库没有自动测试,命名不一致以及大量注释,例如“为什么在这里?”,“不确定是否需要此方法”或“此方法的名称不正确”,并且代码乱七八糟尽管我们使用源代码控制,但仍存在“ Changelogs”。可以说,我们的代码库可以使用重构。 我们总是有修复错误或添加新功能的任务,因此没有时间将代码重构为更好和更模块化的代码,而且似乎也不是优先考虑的事情。 我如何证明重构的价值,以便将其添加到我们的任务列表中?在我进行重构时,请求宽恕而不是允许是值得的吗?

9
重构前如何编写单元测试?
我已经阅读了类似问题的一些答案,例如“重构时如何保持单元测试正常工作?”。就我而言,情况略有不同,因为我得到了一个项目进行审查并符合我们已有的一些标准,目前该项目根本没有测试! 我已经确定了许多我认为可以做得更好的事情,例如不要在服务层中混合DAO类型的代码。 在重构之前,为现有代码编写测试似乎是一个好主意。在我看来,问题是当我进行重构时,这些测试将随着我改变执行某些逻辑的位置而中断,并且这些测试将牢记先前的结构(模拟的依赖关系等)编写。 就我而言,最好的前进方法是什么?我很想围绕重构的代码编写测试,但是我知道我可能会错误地重构事物,从而可能改变期望的行为。 无论是重构还是重新设计,我都很高兴能理解要更正的术语,目前我正在为重构进行以下定义:“按照定义,重构不会改变软件的功能,您将更改其操作方式。”。因此,我不会更改软件的功能,而是会更改软件的方式/位置。 同样,我可以看到这样一种论点,即如果我更改了可以视为重新设计的方法的签名。 这是一个简单的例子 MyDocumentService.java (当前) public class MyDocumentService { ... public List<Document> findAllDocuments() { DataResultSet rs = documentDAO.findAllDocuments(); List<Document> documents = new ArrayList<>(); for(DataObject do: rs.getRows()) { //get row data create new document add it to //documents list } return documents; } } MyDocumentService.java (无论如何都经过重构/重新设计) public …

12
通过代码审查调和童子军规则和机会主义重构
我坚信童子军规则: 始终要比在检出时检查模块中的清洁剂。”不管原始作者是谁,如果我们总是花点力气,不管大小如何,以改进模块。结果是什么?我想所有人都遵循这个简单的规则,我们将会看到软件系统不断恶化的终结,相反,随着系统的发展,我们的系统将逐渐变得越来越好。我们还将看到团队关心整个系统,而不是整个系统。不仅仅是个人照顾自己的一小部分。 我也是机会重构相关思想的坚定信奉者: 尽管在某些地方可以进行一些计划内的重构工作,但我还是鼓励将重构作为一种机会主义活动,它需要在任何时候,任何地方需要清理代码的人(无论谁)进行。这意味着在任何时候,只要有人看到一些不尽如人意的代码,他们都应趁此机会立即将其修复,或者至少在几分钟内 特别注意以下来自重构文章的摘录: 我对任何可能导致机会重构产生冲突的开发实践都保持警惕。我的感觉是,大多数团队都没有进行足够的重构,因此,请注意任何阻碍人们进行重构的事情,这一点很重要。为了避免这种情况的发生,请注意任何时候您都不愿意进行小规模的重构,您肯定只需要一两分钟。任何此类障碍都是应该引起对话的气味。因此,请记下该挫折并与团队联系。至少应该在下一次回顾中讨论它。 在我工作的地方,有一种开发实践会引起严重的摩擦-代码审查(CR)。每当我更改不在“任务”范围内的任何内容时,我的审核员都会对我感到bu异,因为我正在使更改难以审核。当涉及到重构时,尤其如此,因为这使得“逐行”差异比较变得困难。这种方法是这里的标准,这意味着很少进行机会性重构,并且只会进行“计划的”重构(通常太少,太晚)。 我声称这样做的好处是值得的,并且3名审阅者会更加努力(实际上要前后理解代码,而不是仅仅关注变更范围的狭窄范围,因此,审阅本身会更好一些) ),以便接下来的100个阅读和维护代码的开发人员将受益。当我向审阅者提出这个论点时,他们说只要我不在同一CR中,他们的重构就不会有问题。但是我声称这是一个神话: (1)大多数时候,您只有在从事作业时才意识到要重构的内容和方式。正如马丁·福勒(Martin Fowler)所说: 在添加功能时,您意识到要添加的某些代码与某些现有代码包含某些重复项,因此您需要重构现有代码以清理问题……您可能会工作,但意识到如果更改了与现有类的交互,则更好。在您认为自己已完成之前,抓住这个机会。 (2)没有人会喜欢您发布您不应该做的“重构” CR。CR有一定的开销,您的经理不希望您在重构上“浪费时间”。当它与您应做的更改捆绑在一起时,此问题被最小化。 Resharper加剧了这个问题,因为我添加到更改中的每个新文件(而且我事先无法确切知道哪些文件最终会更改),通常充满错误和建议-其中大多数都是应有的且应有的定影。 最终结果是我看到了可怕的代码,然后就把它留在那里了。具有讽刺意味的是,我觉得修复这样的代码不仅不会提高我的声誉,而且实际上降低了我的声誉,并将我描绘成一个“无专心的”家伙,他浪费时间去修复那些没人关心的事情而不是去干他的工作。我对此感到难过,因为我确实鄙视错误的代码,无法忍受观看,更不用说从我的方法中调用它了! 关于如何纠正这种情况有什么想法?

11
如何避免级联重构?
我有一个项目。在此项目中,我希望对其进行重构以添加功能,并且对项目进行重构以添加功能。 问题是,当我完成后,原来我需要做一个小的接口更改以适应它。所以我做了改变。然后,就新类而言,无法使用其当前接口来实现消费类,因此它也需要一个新接口。现在已经三个月了,我不得不解决了几乎不相关的无数问题,而且我正在寻找解决从现在开始经过一年规划的问题,或者只是因为困难而列为无法解决的问题,然后再进行编译再次。 将来如何避免这种级联重构?这仅仅是我以前的课程互相依赖的一种征兆吗? 简要编辑:在这种情况下,重构就是功能,因为重构增加了特定代码的可扩展性并减少了一些耦合。这意味着外部开发人员可以做更多的事情,而这正是我想要提供的功能。因此,原始重构本身不应该是功能上的更改。 我五天前承诺的更大修改: 在开始重构之前,我有一个带有接口的系统,但是在实现中,我只是简单地dynamic_cast通过了所有可能的实现。显然,这意味着您不能一方面从接口继承,其次,对于没有实现访问权即可实现此接口的任何人,这都是不可能的。因此,我决定要解决此问题并开放供公众使用的界面,以便任何人都可以实施,而实施该界面是整个合同所必需的-显然是一项改进。 当我发现并用火杀死所有地方时,我发现一个地方被证明是一个特殊的问题。它取决于所有各种派生类的实现细节以及已经实现但在其他地方更好的重复功能。它可以代替公共接口来实现,而可以重新使用该功能的现有实现。我发现它需要特定的上下文才能正常运行。粗略地说,调用先前的实现看起来像 for(auto&& a : as) { f(a); } 但是,要获得此上下文,我需要将其更改为更类似的内容 std::vector<Context> contexts; for(auto&& a : as) contexts.push_back(g(a)); do_thing_now_we_have_contexts(); for(auto&& con : contexts) f(con); 这意味着对于以前曾经是其中一部分的所有操作f,其中一些操作需要成为g无需上下文的新功能的一部分,而其中某些操作则需要由现在延迟的一部分组成f。但是,并非所有方法都f调用需要或需要此上下文-其中一些需要通过单独的方式获得的独特上下文。因此,对于f最终调用的所有内容(大致来说,几乎所有内容),我必须确定他们需要的上下文(如果有的话),应该从哪里获取以及如何将它们从旧f分为新f与新g。 这就是我最终所处位置的方式。我一直坚持下去的唯一原因是因为无论如何我都需要这种重构。

2
什么是“功能嫉妒”代码,为什么将其视为代码气味?
关于SO的这个问题是关于纠正OP认为是功能嫉妒代码的问题。我看到这个漂亮短语被引用的另一个示例是在developer.SE中最近给出的答案中。尽管我确实在该答案的注释中要求提供信息,但我认为这对遵循Q&A的程序员理解“ 特性嫉妒 ”一词有帮助。如果您认为合适,请随时编辑其他标签。


21
您如何向非技术人员解释重构?
您如何向非技术人员(通常是PHB或客户)解释重构(和技术债务)?(“什么,这要花我一个月的时间而没有明显的区别?!”) 更新感谢到目前为止的所有回答,我认为此列表将提供一些有用的类比,我们可以向相应的人员指出(尽管删除对PHB的引用可能是明智的!)

5
当最终用户的命名法改变时,我们应该在多大程度上重命名代码和数据?
很久以前,我们添加了一项功能,使用户在将图像添加到工作流队列后可以“接受”图像。原来,我们使用了错误的术语,并且用户实际上“批准”了该图像。 在我们的界面上更改“接受接受”很容易,只需替换一个单词即可。但是,我们从CSS类名称到数据库值都使用“ accept”一词对所有层进行了编程。 使按钮变为绿色的CSS类:“ .accepted”; 验证并绑定DOM节点上的类属性的模型方法:“ isAccepted”; JavaScript状态属性:具有“未审阅”,“已接受”和“已发布”的数组; Mysql状态列:ENUM,具有“未审阅”,“已接受”和“已发布”; 测试名称; 替换大多数出现的接受批准很简单(特别是在进行测试时)。迁移数据要困难一点,特别是因为它需要与部署同步。 这个特定的案例很简单,但是在我的职业生涯中,我遇到过类似但更复杂的案例。当文件也被重命名并且在数十台服务器上进行部署时,或者当代理缓存时,将涉及memcached和mysql。 除了接口之外,在所有其他层上都保留“接受”是一个坏主意,因为加入该团队的新程序员可能无法了解导致该决定的历史原因,并且如果接受->赞成,则在含义上是相近的词语被重命名为“排队参加管理层下次地位会议”,这当然没有任何意义。而且,如果我们在这里和那里折衷,就会感觉到,在一些迭代中,用户界面的概念不会影响系统内部,并且我当然不希望在其中一半输出与其内部没有关系的系统上工作。 那么,您是否总是在需要时重命名所有内容?如果这发生在您身上,并且您认为这种权衡不值得,那是不是又回来咬了您?代码注释或开发人员文档是否足以避免此问题?

15
如何处理耗时超过一个冲刺的重构?
我使用的代码库超过50万行代码。迫切需要重构。已经确定了重构工作将比正常的两周冲刺花费更长的时间。正如我在本网站上的其他答案所建议的那样,这些不能分解成较小的任务。产品需要在迭代结束时工作,并且部分重构将使系统处于无法使用的状态,因为项目之间的依赖关系非常糟糕。那么解决这一障碍的最佳方法是什么?我再次提到,将其分解成较小的部分不是一个选择,这已经完成了。 更新:人们似乎需要解释为什么这不能适合2周的冲刺。冲刺中涉及的不仅仅是编写代码。我们的政策是没有测试就没有代码。该策略并不总是存在,并且代码库中的很大一部分都没有。另外,我们的某些集成测试仍然是手动测试。问题不在于重构本身如此之大。事实是,小的更改会影响系统的许多部分,因此我们需要确保这些部分仍然可以正常运行。 因为我们有每月的修补程序,所以我们不能推迟或延长冲刺。因此,经过sprint的更改无法停止将其他工作添加到此修补程序中。 重构与重新设计:仅仅因为我们的开发过程效率不足,无法在两周的周期内完成此重构,所以不能保证将其重命名为重新设计。我想相信,随着我们流程的改进,将来我们可以在两周的周期内完成完全相同的任务。这里讨论的代码很长时间都不需要更改,并且相当稳定。现在,随着公司的发展方向变得更加适应变化,我们希望代码库的这一部分与其余部分一样具有适应性。这需要重构。根据这里的答案,很明显,在正常的sprint的时间范围内缺少必要的脚手架来进行此重构。 回答: 我将采用科宾·马奇(Corbin March)首次提出的分支与合并方法,以便我们可以更多地了解这些问题领域以及如何识别缺失的测试。我认为,向前迈进,我们应该采用Buhb建议的方法,确定缺少测试的区域并先实施这些区域,然后再进行重构。这将使我们能够保持正常的两周冲刺周期,就像这里的许多人一直在说的那样,重构应该总是如此。

10
如何最好避免编写writing肿的GUI代码?
我发现每当使用GUI代码时,该代码往往会比其他类型的代码膨胀更快。似乎也很难重构。在其他类型的代码中,我可以轻松地重构-我发现可以将较大的类分解为较小的功能-对于大多数GUI框架,我经常绑定到需要我的小部件/控件/任何类的框架在窗口小部件/控件/任何地方更直接地实现更多功能。有时这是由于需要(a)继承一些基本控件/控件/事物,或者(b)需要访问受保护的方法。 我通常还必须(例如)通过信号/事件/来自框架的任何内容来响应各种各样的输入,以实现与用户交互的所有模式。我可能需要一个GUI小部件/控件来处理各种各样的输入/输出,其中可能包括: 右键单击/上下文菜单 对上下文菜单中的选择做出反应-可能很多 绘制GUI的一种特殊方法 对键盘输入做出反应 按钮,复选框, 等 ...一直在GUI之下管理代表业务逻辑的类。 一个简单而直接的GUI可以使其代码快速增长,即使分离出业务逻辑并使用MVC时,我也发现GUI代码具有很大的吸引力。 有什么方法可以以合理的方式管理GUI代码,并避免使其成为损坏的窗口?还是大量随机事件处理程序/重写方法确实是我们可以为GUI代码做的最好的事情?
48 refactoring  gui 

7
如何衡量重构的潜在价值
在具有技术债务的旧的大型项目中,如何可靠地估算或衡量重构代码的收益? 例如,假设您在软件堆栈解决方案中有一些组件是用较旧的语言编写的,而某些较后的组件是用较新的语言编写的。开发团队将不断向该解决方案添加新功能和错误修复。 开发人员建议用新版本替换现有的旧语言组件将是“一件好事”。但是,这项工作不会增加任何额外的功能,这将花费x开发日。 销售人员建议添加“一项很棒的新功能”。公司通过使用公式来衡量他的建议的价值。即。它将在t年内以x开发日的工作成本为公司赚取F百万英镑。 公司如何以有意义的方式增加重构建议的成本?在什么情况下,这可能是公司最赚钱的选择?

8
代码维护:在扩展新代码时是否保持一致的错误模式?
我必须扩展项目的现有模块。我不喜欢它的完成方式(涉及很多反模式,例如复制/粘贴的代码)。由于多种原因,我不想执行完整的重构。 我是不是该: 使用现有约定创建新方法,即使我觉得错了,也可以避免对下一个维护者造成混淆并与代码库保持一致? 要么 尝试使用我感觉更好的方法,即使它在代码中引入了另一种模式? 精确度在第一个答案后进行了编辑: 现有的代码不是一团糟。很容易理解和理解。但是,它引入了许多可以通过良好设计避免的样板代码(结果代码可能会变得更难遵循)。在我当前的情况下,这是一个很好的旧JDBC(内置弹簧模板)DAO模块,但是我已经遇到了这个难题,我正在寻求其他开发人员的反馈。 我不想重构,因为我没有时间。而且即使有时间,也很难证明一个完整的正常工作的模块需要重构。重构成本将超过其收益。请记住:代码并不凌乱或过于复杂。我不能在那里提取一些方法并在这里介绍一个抽象类。这在设计中更是一个缺陷(我认为极端“保持愚蠢简单”的结果) 因此,也可以这样问这个问题: 作为开发人员,您是喜欢维护简单的愚蠢无聊的代码,还是希望有一些帮助程序来代替您的愚蠢无聊的代码? 最后一种可能性的缺点是,您必须学习一些知识,也许您还必须维护简单的愚蠢无聊代码,直到完成完整的重构为止)


6
处理重构大文件的最佳方法是什么?
我目前正在做一个更大的项目,不幸的是其中有些文件的软件质量准则并不总是遵循的。这包括大文件(读取2000-4000行),这些文件显然包含多个不同的功能。 现在,我想将这些大文件重构为多个小文件。问题是,由于它们很大,因此不同分支上的多个人(包括我)正在处理这些文件。因此,我无法真正从开发和重构中分支出来,因为将这些重构与其他人的更改合并将变得很困难。 当然,我们可以要求每个人重新合并以开发,“冻结”文件(即,不再允许任何人对其进行编辑),重构然后“取消冻结”。但这也不是一件好事,因为这将要求每个人在重构完成之前基本上停止对这些文件的工作。 因此,有没有一种方法可以重构,不要求其他人停止工作(很长时间)或合并其功能分支以进行开发?

6
为什么SQL不可重构?[关闭]
每个人都知道新开发人员会编写长函数。随着您的进步,您会更好地将代码分解成较小的部分,而经验告诉您这样做的价值。 输入SQL。是的,SQL的代码思考方式与过程的代码思考方式不同,但是该原理似乎同样适用。 假设我有一个采用以下形式的查询: select * from subQuery1 inner join subQuerry2 left join subquerry3 left join join subQuery4 使用一些ID或日期等 这些子查询本身很复杂,可能包含自己的子查询。在任何其他编程上下文中,我都认为复杂子查询1-4的逻辑与将它们全部连接在一起的父查询一致。看起来很简单,应该将那些子查询定义为视图,就像如果我在编写过程代码时将它们作为函数一样。 那么,为什么不这样做呢?人们为什么如此频繁地编写这些冗长的整体SQL查询?SQL为什么不鼓励广泛使用视图,就像过程编程鼓励广泛使用函数一样。(在许多企业环境中,创建视图甚至都不是一件容易的事。需要请求和批准。想象一下,其他类型的程序员每次创建函数时是否都必须提交请求!) 我想到了三个可能的答案: 这已经很普遍了,我正在与经验不足的人一起工作 经验丰富的程序员不会编写复杂的SQL,因为他们喜欢用过程代码解决硬数据处理问题 还有别的

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.