Questions tagged «refactoring»

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

5
您是否应该重构专注于新功能的项目中未破坏的现有代码?
给定一个旨在为应用程序添加新功能的小型项目,所引入的更改涉及一些现有代码,涉及在某些领域中进行更新。在实施期间,我发现其中一些更新的代码具有重构的候选对象。 这是否是一个适当的重构时间,从而又需要对受影响的那些组件进行回归测试(因此可能引入的范围最初不是项目的一部分)?还是我应该推迟,完成功能,也许有一个单独的项目进行重构(尽管我有点犹豫,因为业务用户可能不会完全赞助一个不添加任何功能的项目,除非他们重视代码的可维护性...)?

3
什么时候不推荐使用Java
作为重构工作或正在进行的开发的一部分,某种方法或整个类可能会在某种意义上过时。Java支持该@Deprecated注释,以指示可能存在更好的方式来处理所涉及的功能。我想这在公共API中特别有用,在公共API中可能不知道删除API部分的影响。对于非公共API和使用版本控制系统的项目(从某种意义上讲,可以撤消删除操作),什么时候宜弃用而不是删除过时的元素?

2
如何组织重复代码?
我的团队创建了很多一次性的Web表单。这些表格中的大多数仅发送电子邮件,而一些表格进行简单的数据库写入。 现在,每种形式都存在于Visual Studio Team Foundation Server中自己的单独解决方案中。这意味着我们有将近100个不同的表单项目,这使得保持一致性变得很困难。每种形式都是唯一的,因为字段是不同的,但是它们几乎都做相同的事情。 我希望以某种方式压缩这些内容,并且我确实可以使用一些指导。 我是否应该尝试在其中包含所有表单项目的情况下创建一个解决方案文件?尽管我可以创建一些帮助程序类来帮助进行电子邮件格式化等,但是没有很多管道代码。能够在项目之间共享CSS,JavaScript,控件和图像将非常有帮助。 既然我们是Microsoft商店,那么针对这种特定情况,通过Webforms使用MVC之类的东西有什么明显的好处?整个MVC的概念使我受宠若惊,但是如果该表格仅发送电子邮件,是否可以帮助我更有效地整理15字段数据收集表格?我想到的表单具有很多内置的逻辑,可以根据用户的响应显示和隐藏字段,并且似乎使用MVC和jQuery的效率较低。

4
有什么好的方法可以清理旧项目?
我有大约2年前写的一些软件,并且需要添加一些功能。我已经意识到这是在一个烂摊子,和我有冲动走动的一切,收拾一下,等我读过的软件乔尔约不重新启动的文章,让最新最好的方式前进?

6
实施SRP的实际方法是什么?
人们简单地检查班级是否违反单一责任原则的实用技术是什么? 我知道一个班级应该只有一个改变的理由,但是那句话在某种程度上缺乏真正实现这一改变的实用方法。 我发现的唯一方法是使用句子“……本身应该……”。其中第一个空格是类名称,第二个空格是方法(职责)名称。 但是,有时很难确定责任是否确实违反了SRP。 还有更多检查SRP的方法吗? 注意: 问题不在于SRP意味着什么,而是关于检查和实施SRP的实用方法或一系列步骤。 更新 我添加了一个明显违反SRP的示例类。如果人们可以以此为例来说明他们如何遵循单一责任原则,那将是很好的。 这个例子是从这里开始的。

5
如何重构现有的Web应用程序?
最近我一直在阅读和思考很多,得出的结论是,也许我应该重新考虑我的Web开发策略。我正在做大量的即时编程,在过去两年中,我一直在研究PHP Web应用程序,当一个小工具变成一个相当大的项目时,它可能已经开始了。但是我和我的前任有很多遗留代码,这些代码片段在当时可能很有意义,但是现在我在质疑所说代码的实际形式。而且,直到最近,诸如单元测试和测试驱动开发之类的东西才在我的范围之内。 那么您将如何重构Web应用程序?我应该寻找什么东西,以什么顺序排列?浏览器游戏与功能性网络应用程序又如何?那么方法上会有区别吗?

4
以适当的方式将条件替换为多态吗?
考虑两个类Dog并且Cat都符合Animal协议(就Swift编程语言而言。这将是Java / C#中的接口)。 我们有一个屏幕,显示猫和狗的混合列表。有一个Interactor类处理幕后逻辑。 现在,我们要向用户显示删除猫的确认警报。但是,需要立即删除狗而不发出任何警报。有条件的方法如下所示: func tryToDeleteModel(model: Animal) { if let model = model as? Cat { tellSceneToShowConfirmationAlert() } else if let model = model as? Dog { deleteModel(model: model) } } 该代码如何重构?闻起来很香

4
好的代码风格可在任何地方引入数据检查?
我有一个足够大的项目,我再也无法保持每个方面的头脑。我正在处理其中的许多类和函数,并且正在传递数据。 随着时间的流逝,我注意到我一直在出错,因为我忘记了将数据传递给不同的函数时数据必须具有的精确格式(例如,一个函数接受并输出一个字符串数组,另一个函数是我后来写的,接受保留在字典等中的字符串,因此我必须将正在使用的字符串从数组中的字符串转换为字典中的字符串)。 为了避免总是要弄清楚什么地方断了,我开始将每个函数和类都视为“孤立实体”,因为它不能依赖外部代码为其提供正确的输入,而必须自己执行输入检查(或,在某些情况下,如果数据格式错误,请重铸数据。 这大大减少了我花费在确保传递的数据“适合”每个函数上的时间,因为当某些输入不正确(有时甚至纠正)时,类和函数本身会警告我,而我不会必须与调试器一起遍历整个代码,以找出问题的根源。 另一方面,这也增加了整体代码。 我的问题是,此代码样式是否适合解决此问题? 当然,最好的解决方案是完全重构项目,并确保数据具有所有功能的统一结构-但是由于该项目不断增长,因此我最终将花费更多的时间并担心干净的代码,而不是实际添加新内容。 (仅供参考:我仍然是一个初学者,因此,如果这个问题太天真,请原谅;我的项目是使用Python。)

6
如何避免在次优设计中无休止地迭代?
因此,可能像许多人一样,我经常发现自己对设计问题感到头疼,例如,有些设计模式/方法似乎可以直观地解决问题并具有预期的好处。通常会有一些警告,如果没有某种工作就很难实施模式/方法,而这周围的工作否定了模式/方法的好处。我可以很轻松地结束许多模式/方法的迭代,因为可以预见的是,几乎所有的模式/方法在现实世界中都存在一些非常重要的警告,在这些情况下,根本没有一个简单的解决方案。 例: 我将给您一个假设的示例,大致基于我最近遇到的一个真实示例。假设我想在继承上使用合成,因为过去继承层次结构阻碍了代码的可伸缩性。我可能会重构代码,但随后发现在某些上下文中,超类/基类只是需要在子类上调用功能,尽管尝试避免这样做。 下一个最好的方法似乎是实现一半委托/观察者模式和一半组合模式,以便超类可以委托行为,或者子类可以观察超类事件。然后,该类的可伸缩性和可维护性较差,因为它不清楚应如何扩展,而且扩展现有的侦听器/代理也很棘手。同样,信息也隐藏得不好,因为人们开始需要了解实现以了解如何扩展超类(除非您非常广泛地使用注释)。 因此,在此之后,我可能会选择完全使用观察者或委托人来避免因混淆大量方法而带来的弊端。但是,这有其自身的问题。例如,我可能会发现我最终需要观察者或代表来应对越来越多的行为,直到我几乎需要针对每种行为的观察者/代表。一种选择可能是只为所有行为提供一个大的侦听器/代理,但是实现类最终会带有许多空方法等。 然后,我可以尝试另一种方法,但是与此同时存在很多问题。然后是下一个,然后是下一个,依此类推。 当每种方法似乎都存在其他问题时,这种迭代过程将非常困难,并导致某种设计决策瘫痪。无论使用哪种设计模式或方法,都很难接受代码最终同样会带来问题。如果我最终陷入这种情况,是否意味着问题本身需要重新考虑?别人遇到这种情况时会做什么? 编辑: 似乎有一些我想清除的问题的解释: 我将OOP完全排除在问题之外,因为事实证明它实际上并不是特定于OOP的,而且很容易误解我在传递OOP时所做的一些评论。 有些人声称我应该采取迭代的方法并尝试不同的模式,或者当它停止工作时我应该放弃一个模式。这是我首先要参考的过程。我认为这个例子很清楚,但是我可以更清楚一点,所以我编辑了问题。

5
对相似的功能使用不同的模式
我是该项目的唯一开发人员,就像其他软件项目一样,将来可能会被其他人采用。 假设我使用模式X来实现功能A。在开发和完成功能之后,我意识到可以使用我刚刚学习的模式Y来实现相同的功能。但是功能A运行良好,并且从X到Y的重构既耗时又无济于事。 然后是实现功能B的时候了。它与A相似,但是这次我想借此机会使用模式Y。我对最终结果感到满意,比使用功能A更好,但是现在我的代码使用了两个具有相似特征的X和Y不同的图案。 但是没有真正的理由使用不同的模式,除了以下事实:构建功能AI的技能不足以使用与功能B相同的模式。 请注意,此问题不是针对给定问题选择正确的模式;这是在代码库中共存的两种模式,用于解决类似的问题,如果有足够的时间进行重构,则可以将其减少为一种。 该代码闻到了吗? 保持这样的源代码有什么缺点? 我应该只使用一种模式吗?即重构A以使用Y或在编写B时继续使用X? 从源头上,我该如何传达出针对相似功能存在两种不同模式的原因基本上是没有原因的? 我是否担心下一位开发人员对我的代码的看法?

4
减少类的复杂性
我已经查看了一些答案并在Google上进行了搜索,但是找不到任何有用的东西(即不会产生尴尬的副作用)。 总的来说,我的问题是我有一个对象,需要对它执行长时间的操作。我将其视为一种装配线,例如制造汽车。 我相信这些对象将称为“ 方法对象”。 因此,在此示例中的某个点上,我将拥有一个CarWithoutUpholstery,然后需要在其上运行installBackSeat,installFrontSeat,installWoodenInserts(这些操作不会互相干扰,甚至可以并行执行)。这些操作由CarWithoutUpholstery.worker()执行,并产生一个新的对象,该对象将是CarWithUpholstery,然后在其上运行cleanInsides(),verifyNoUpholsteryDefects()等。 单个阶段中的操作已经是独立的,也就是说,我已经在努力应对可以按任何顺序执行的子集(可以按任何顺序安装前排和后排座椅)。 我的逻辑当前使用反射来简化实现。 也就是说,一旦有了CarWithoutUpholstery,该对象就会检查自身是否有名为performSomething()的方法。此时,它执行所有这些方法: myObject.perform001SomeOperation(); myObject.perform002SomeOtherOperation(); ... 同时检查错误和内容。虽然操作的顺序是不重要的,我已经在指定情况下,我曾经发现毕竟一些顺序很重要,一个字典顺序。这与YAGNI矛盾,但是它花费很少-简单的sort()-并且可以节省大量的方法重命名(或引入其他执行测试的方法,例如方法数组)的费用。 一个不同的例子 让我们说,除了要制造汽车外,我还必须编辑某人的秘密警察报告,并将其提交给我的邪恶霸主。我的最后一个对象将是ReadyReport。为了构建它,我首先收集基本信息(姓名,姓氏,配偶...)。这是我的A阶段。根据是否有配偶,我可能不得不进入B1或B2阶段,并收集一两个人的性行为数据。这是由对不同的Evil Minions的几个不同的查询所组成,它们控制着夜生活,街拍,性用品商店的销售收据以及不收什么。等等等等。 如果受害者没有家庭,我什至不会进入GetInformationAboutFamily阶段,但是如果我这样做了,那么我是首先瞄准父亲还是母亲还是兄弟姐妹(如果有)就没有关系了。但是,如果我还没有执行FamilyStatusCheck,那我就无法做到这一点,因此它属于早期阶段。 一切都很棒... 如果我需要一些其他操作,我只需要添加一个私有方法, 如果该操作在多个阶段都是通用的,那么我可以让它从超类继承, 操作简单且自成体系。任何其他操作都不需要从任何操作中获得任何价值(在不同阶段执行的操作), 线下的对象不需要执行许多测试,因为如果其创建者对象首先没有验证这些条件,它们甚至可能不存在。即,在将插入物放入仪表板,清洁仪表板并验证仪表板时,我不需要验证仪表板是否确实存在。 它便于测试。我可以轻松模拟部分对象并在其上运行任何方法,并且所有操作都是确定性的黑匣子。 ...但... 当我在我的方法对象之一中添加最后一个操作时,就会出现问题,这导致整个模块超过了强制性的复杂性指标(“少于N个私有方法”)。 我已经在楼上解决了这个问题,并建议在这种情况下,私有方法的丰富并不是灾难的故事。复杂性是存在的,但它的存在,因为操作是复杂的,实际上它不是那么复杂-它只是长。 以邪恶的霸王为例,我的问题是邪恶的霸王(又名不容否认的他)要求了所有饮食信息,我的饮食奴才告诉我,我需要查询餐馆,小厨房,街头小贩,无牌街头小贩,温室所有者等,以及邪恶的(sub)Overlord(众所周知的也不应被拒绝的他)抱怨我在GetDietaryInformation阶段执行了太多查询。 注意:我知道从多个角度来看这根本不是问题(忽略可能的性能问题等)。发生的一切是,一个特定的指标不满意,对此有充分的理由。 什么我想我能做到 除了第一个以外,所有这些选择都是可行的,而且我认为是可以辩护的。 我已经证实自己可以偷偷摸摸,并声明一半的方法protected。但是我会利用测试程序中的弱点,除了在被抓住时证明自己是合理的之外,我也不喜欢这样。另外,这是权宜之计。如果所需操作次数加倍怎么办?不太可能,但是那又如何呢? 我可以将此阶段任意拆分为AnnealedObjectAlpha,AnnealedObjectBravo和AnnealedObjectCharlie,并使每个阶段要执行的操作占三分之一。我的印象是,这实际上增加了复杂性(增加了 N-1个类),除了通过测试之外没有任何好处。我当然可以认为,CarWithFrontSeatsInstalled和CarWithAllSeatsInstall在逻辑上是连续的阶段。Alpha后来要求使用Bravo方法的风险很小,如果我打得很好的话,风险甚至会更低。但是还是。 我可以将一个远程相似的不同操作组合在一起。performAllSeatsInstallation()。这只是权宜之计,并且确实增加了单个操作的复杂性。如果我需要以不同的顺序执行操作A和B,并且将它们打包在E =(A + C)和F(B + D)内,则必须解开E和F并重新整理代码。 我可以使用lambda函数数组,并完全避开检查,但是我发现这很笨拙。但是,这是迄今为止最好的选择。它会摆脱反思。我遇到的两个问题是,可能会要求我重写所有方法对象,不仅是假设对象,CarWithEngineInstalled而且这虽然是很好的工作安全性,但实际上并没有那么大的吸引力。并且代码覆盖率检查器存在lambda 问题(可以解决,但仍然存在)。 所以... 您认为哪个是我最好的选择? 有没有我没有考虑过的更好的方法?(也许我最好打扫卫生,直接问一下是什么?) 这种设计是否存在绝望的缺陷,我最好承认失败与否-这种体系结构?这对我的职业生涯不利,但是从长远来看,编写错误的代码会更好吗? 我当前的选择是否真的是“唯一的方式”,我需要努力获得更好的质量指标(和/或仪器)?对于这最后一个选项,我需要参考...我不能只在抱怨的同时对@PHB挥手,这不是您要查找的指标。不管我想要多少

3
我必须妥协:DRY还是Command-Query-Separation?
我最近正在重构既是命令又是查询方法的方法。 将其分为一个命令方法和一个查询方法后,我发现代码中现在有多个地方可以调用命令,然后从查询中获取值,这似乎违反了DRY原理。 但是,如果我要将通用代码包装到一个方法中,则该方法既是命令又是查询。这可以接受吗?

3
重构大型方法以确保我不会破坏任何内容时,会有什么帮助?
我目前正在重构大型代码库的一部分,而没有任何单元测试。我试图以残酷的方式重构代码,即试图猜测代码在做什么,什么更改不会改变它的含义,但是没有成功:它随机破坏了整个代码库的功能。 请注意,重构包括将旧版C#代码移动到更具功能性的样式(旧版代码未使用.NET Framework 3和更高版本的任何功能,包括LINQ),在代码可能会从中受益的地方添加了泛型,等等。 考虑到要花多少钱,我不能使用形式化方法。 另一方面,我认为至少要严格遵循“任何重构的遗留代码都应带有单元测试”的规则,无论它要花多少钱。问题在于,当我重构500 LOC私有方法的一小部分时,添加单元测试似乎是一项艰巨的任务。 什么可以帮助我了解哪些单元测试与给定的代码相关?我猜测对代码进行静态分析会有所帮助,但是我可以使用哪些工具和技术: 确切知道我应该创建什么单元测试, 和/或知道我所做的更改是否以与现在不同的方式影响了原始代码?

7
临时变量与线长要求
我一直在阅读Martin Fowler的Refactoring。它通常很棒,但是Fowler的建议之一似乎引起了一些麻烦。 Fowler建议您使用查询替换临时变量,因此,不要这样做: double getPrice() { final int basePrice = _quantity * _itemPrice; final double discountFactor; if (basePrice > 1000) discountFactor = 0.95; else discountFactor = 0.98; return basePrice * discountFactor; } 您可以使用辅助方法: double basePrice() { return _quantity * _itemPrice; } double getPrice() { final double discountFactor; if (basePrice() > …

5
如何对重构为策略模式的功能进行单元测试?
如果我的代码中有一个像这样的函数: class Employee{ public string calculateTax(string name, int salary) { switch (name) { case "Chris": doSomething($salary); case "David": doSomethingDifferent($salary); case "Scott": doOtherThing($salary); } } 通常,我会使用工厂类和策略模式将其重构为使用多态性: public string calculateTax(string name) { InameHandler nameHandler = NameHandlerFactory::getHandler(name); nameHandler->calculateTax($salary); } 现在,如果我正在使用TDD,那么calculateTax()在重构之前,我将对原始版本进行一些测试。 例如: calculateTax_givenChrisSalaryBelowThreshold_Expect111(){} calculateTax_givenChrisSalaryAboveThreshold_Expect111(){} calculateTax_givenDavidSalaryBelowThreshold_Expect222(){} calculateTax_givenDavidSalaryAboveThreshold_Expect222(){} calculateTax_givenScottSalaryBelowThreshold_Expect333(){} calculateTax_givenScottSalaryAboveThreshold_Expect333(){} 重构后,我将具有Factory类NameHandlerFactory和的至少3个实现InameHandler。 我应该如何重构我的测试?我应该claculateTax()从中删除单元测试,EmployeeTests并为的每个实现创建一个Test类InameHandler吗? 我也应该测试工厂课程吗?

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.