我最近开始了一份新工作,正在处理一个非常大的应用程序(15M loc)。在我之前的工作中,我们有一个类似的大型应用程序,但是(无论好坏,我们都使用了OSGi),这意味着该应用程序被分解为许多微服务,这些微服务可以独立更改,编译和部署。新应用程序只是一个大型代码库,可能包含几个.dll。

所以我需要更改此类的接口,因为那是我老板要我做的。最初,他们在编写某些假设时并没有很好地推广,而且有一段时间他们一直在避免重构问题,因为它是如此紧密地耦合在一起。我更改了界面,现在有25000多个错误。有些错误是在具有重要发音的类中出现的,例如“ XYZPriceCalculator”,它们应该不会再次损坏。但是在解决所有错误之前,我无法启动应用程序以检查其是否正常运行。而且许多单元测试要么直接引用该接口,要么耦合到引用该接口的基类,因此,仅对其进行修复本身就是一项巨大的任务。另外,我真的不知道所有这些部分是如何组合在一起的,所以即使我可以开始使用它,我也不真正知道如果事情破裂了会怎样。

我我上一份工作从未真正遇到过这样的问题。我该怎么办?

评论

您需要向我们提供有关错误的种类以及“此类”是什么的更多信息,我们不介意读者。

“超过25000个错误”在VS中显示的数字通常是错误的。有一些错误,但是由于经常使用的dll的构建被破坏,其他构建也确实失败了,从而增加了天文错误数。我总是从在构建输出而不是在错误列表中找到的第一条错误消息开始修复。

我希望看到您所更改方法的前后签名。顺便说一句-25k的错误听起来确实不胜枚举。乏味是的,令人生畏的,是的,难以管理,没有。

公共接口是合同。不要打破这样的合同-创建新的合同。

25000个错误!?休斯顿,我们遇到了问题。一定要撤消更改并与您的经理交谈,向他解释说您可能必须完全创建一个新界面。

#1 楼

25000个错误基本上意味着“别碰那个”。改回来。创建一个具有所需接口的新类,然后将类的使用者慢慢移至新类。根据语言的不同,您可以将旧类标记为已弃用,这可能会引起各种编译器警告,但实际上并不会破坏您的构建。

不幸的是,这些事情发生在旧代码库中。除了慢慢使事情变得更好以外,您无能为力。创建新类时,请确保已正确测试它们并使用SOLID原理创建它们,以便将来更容易更改它们。

评论


它不一定必须是新类。根据语言和环境的不同,它可能是函数,接口,特征等。

– Jan Hudec
16年11月4日在7:23

如果旧接口可以被新接口周围的兼容性包装所代替,则也有帮助。

– Jan Hudec
16年11月4日在7:24

有时候,实际上有25000个错误意味着我们从不敢碰这个问题,但是既然新来者已经到来,就让他完成清理Augean-stables的任务。

–mouviciel
16年11月4日在10:46



@theDmi:我同意,1个更改和25,000个错误最有可能意味着最多2.5k个更改,并且发现它大约有250个,我不会感到惊讶。无论哪种方式都可以做很多工作,但是可行。

– jmoreno
16年11月4日在11:04

一次更改即可修复所有25000个错误。如果我破坏了一个巨大的继承体系的基类,那么每个派生类都会产生关于无效基类的错误,每次使用这些类都会产生关于该类不存在的错误,等等。想象一下它是“ getName”,我添加了一个争论。现在,“ HasAName”实现类中的覆盖无效(错误),并且从它继承的所有内容现在都会生成错误(所有1000个类),并且每次我创建其中任何一个的实例时(每个类24x)平均)。解决方法是……一行。

– ak牛
16年11月4日在13:42

#2 楼

用重构进行划分和征服

通常,将需要进行的更改分解为较小的步骤通常会有所帮助,因为您可以按照不破坏软件的方式执行大多数较小的步骤所有。重构工具对此类任务有很大帮助。

划分

首先,确定总结出的最小可能变化(就逻辑变化而言,而不是变化的LoC而言)您想要实现的改变。尤其要尝试分离出纯重构的步骤,并且可以通过工具执行这些步骤。

征服

对于像您这样的复杂情况,最好在以下位置执行一个小的重构一段时间,然后解决问题,以便所有连续集成系统都可以验证更改,并且测试团队也可以看一下。这将验证您执行的步骤。

要进行特定的重构,对于您拥有要更改的方法的25,000个调用站点的情况,您绝对需要工具支持。也许搜索替换也可以,但是对于这样的紧急情况,我会感到害怕。

示例

例如在C#中,这是可能的使用Resharper更改方法的签名。如果更改足够简单,例如添加新参数,然后您可以指定应在调用站点使用哪个值,否则将出现编译错误。

您将立即处于无错误的代码基础,并且可以运行所有将通过的单元测试,因为这仅是重构。

方法签名后看起来不错,您可以去替换Resharper作为新引入的参数的参数添加的值。这不再是重构,但是您有一个无错误的代码库,可以在每行更改之后运行测试。

有时不起作用

对于像您这样拥有大量呼叫站点的情况,这是一种非常有用的方法。而且您现在已经有了可以使用的软件,因此可以进行一些小的重构步骤来稍微更改签名,然后再进行另一个签名。太复杂,无法分解成较小的变化。但是,这种情况很少见。将问题分解为较小的问题通常表明这是可能的。

评论


这个。如果可以,请重构(安全),否则需要适当的迁移。

–sleske
16年11月4日在7:46

出于对任何事物的热爱,请利用您的IDE内置的重构工具,而不是仅在本地更改(例如)方法签名,然后全面解决所导致的错误。

– KlaymenDK
16年7月7日在13:14

#3 楼

与老板明确您的任务,以帮助他理解问题和作为专业软件开发人员的需求。

如果您是团队的一员,请寻找首席开发人员并向他寻求建议。

祝你好运。

评论


这是我要采取的第一步-“我是大三,我的老板告诉我要做一件事,现在我收到了一个非常大的错误消息,但我的老板没有告诉我。”步骤1:“嘿,老板,我做了这件事,但是现在我收到2万5千个错误。这应该发生吗,还是...”

– Pimgd
16年11月4日在10:22

#4 楼

不要碰它不要做任何事情。

相反,请坐在椅子上大喊“ Heeeeelp !!!!!”尽可能大声。

好吧,不完全是这样,但请向您的任何高级同事征求意见。如果您有25,000个错误,则不纠正错误,而是要纠正导致错误的原因。而且,一位高级同事应该能够为您提供建议,如何进行老板想要的更改,而不会涉及25,000个错误。有多种方法可以执行此操作,但是什么是好方法取决于您的具体情况。

也许老板告诉你的高级同事做同样的改变,他们说“不”。因为他们知道会发生什么。这就是为什么给你这份工作。

评论


这绝对是要记住的重要事情。如果新员工在很大程度上具有雄心壮志,那么他们可能会勤奋(易变)来完成真正的大任务,最终只能获得5字节的内存优势,或者在以后重新编码和维护时更具逻辑性。

–user64742
16年11月6日,2:10

@TheGreatDuck:告诉我,您从未见过在任何地方都使用过且在任何地方都出错的接口。我肯定有

–约书亚
16年8月8日在4:18

@Joshua甚至和我刚才说的都不相关。有时,修复一个小错误并非总是最聪明的主意,它意味着重写10,000多行代码。不幸的是,一个新员工可能很容易被骗,使10名通宵工作的人整夜工作,重写代码以打动老板并完成工作。当然,这是一件很棒的事,但有时足够了。您只需要接受该错误的存在即可。

–user64742
16年11月8日在14:17

@Joshua顺便说一句,我之所以加入这个社区是因为我的热门问题提要中出现了这个问题。我没有像这样的大规模设计经验。我只是同意这个人的观点。

–user64742
16年11月8日在14:18

#5 楼

根深蒂固的API不能简单地更改。如果您确实需要更改它们,请对它们作废并/或记录为已弃用(通过语言允许的任何方式),并记录应该使用哪个API。然后可以逐步淘汰旧的API ...可能很慢,具体取决于您用于重构的时间预算。

#6 楼

评估

评估是否需要进行此更改,或者是否可以添加新方法并弃用其他方法。

转发

如果需要进行更改;然后需要一个迁移计划。

第一步是引入新方法,并让旧方法按摩其参数,以便可以调用新方法。这可能需要对一些事情进行硬编码。

这是一个提交点:检查所有测试是否通过,提交,推送。

迁移

忙碌的工作正在迁移所有调用者将旧方法改为新方法。幸运的是,多亏了货运代理,它可以逐步完成。

所以继续吧;请不要犹豫使用工具(sed是最基本的工具,还有其他工具)。

将旧方法标记为已弃用(提示切换到新方法);它可以帮助您发现是否忘记了任何内容,并且如果您在工作时同事向旧方法引入了调用,将会有所帮助。

这是一个提交点(或者可能是几个提交点):检查所有测试是否通过,提交,推送。

删除

经过一段时间(可能只有一天),只需删除旧方法。

评论


sed可能不是一个好主意……实际上可以“理解”语言并且不会进行意外更改的东西会更好。

– wizzwizz4
16年11月5日在20:02

@ wizzwizz4:不幸的是,我发现很少有工具能够很好地理解C ++语言。大多数工具似乎都可以重命名,仅此而已。当然,仅重命名确切的方法调用(而不重命名任何重载或无关的但类似命名的方法调用)已经令人印象深刻,但是对于任何更复杂的操作来说都是不够的。至少,您将需要具备以下能力:(1)随机播放参数,(2)将转换应用于给定参数(例如,调用.c_str())并引入新的参数。 sed kinda工作正常,编译器随后发现了问题。

– Matthieu M.
16年11月6日在12:07

sed(或ed)对于这种事情就足够了-只要在提交前正确检查了diff。

– Toby Speight
16年11月7日在16:19

这是html的TCRR,是吗? :)

–丹尼尔·斯普林格(Daniel Springer)
16年7月7日在23:38

#7 楼

如果您对方法签名的更改仅是名称更改,则简单的解决方案是使用工具来自动化25,000个引用所讨论方法的类中的更改。

我假设您只是简单地手动编辑了代码,这引起了所有错误。我还假定您熟悉Java(请参阅对OSGi的参考),因此例如在Eclipse(我不知道使用哪个编程环境,但是其他环境具有类似的重构工具)中,则可以使用“重构->重命名”更新对方法的所有引用,这应该不会给您带来任何错误。

如果要对方法签名进行其他更改,而不仅仅是简单地重命名(更改参数的数量或类型),则可以使用“重构->更改方法签名”。但是,正如其他答案所暗示的那样,您可能必须更加小心。同样,不管更改的类型如何,将所有这些更改都提交到繁忙的代码库中仍然是一项艰巨的任务。

评论


OP特别指出OSGi是他们先前的工作,因此在这里并不重要。

–用户
16年11月5日在13:38

@MichaelKjörling如果OP以前的工作是Java程序员,那么他们也是从事这项工作的Java程序员的机会要多得多。

–丰富
16年11月7日在10:11

@MichaelKjörling我想给出具体的建议,因为OP熟悉Java,所以使用Eclipse进行重构。我想,OP实际上是否在当前项目中使用Java并不那么重要,但是我应该澄清一下答案。谢谢。

– MikkelRJ
16年11月9日在7:44

#8 楼

这是我的贡献。


我最近开始了新工作,当时我正在处理一个很大的
应用程序(1500万行代码)。


您可能不熟悉该项目及其“功能”。在键入一行代码之前,熟悉该项目很重要。因此,请回滚您的更改并从分析代码开始。 (至少是受影响的人)

了解现有的解决方案可以使您更好地了解所要解决的问题。根据解决方案及其重要性的相关性。

正如@Greg所指出的那样,您应该能够测试现有代码以具有可与之进行比较的有效引用(回归测试)。您的解决方案应该能够产生与现有解决方案完全相同的结果。在此阶段,您不必担心结果是否正确。第一个目标是重构,而不是修复错误。如果现有解决方案显示“ 2 + 2 = 42”,那么您的解决方案也应该如此。如果它没有引发异常,那么您也不应抛出异常。如果返回空值,您的也应该返回空值。等等。否则,您将损害25k行代码。

这是为了实现复古兼容性。

为什么?因为现在,这是成功重构的唯一保证。


许多单元测试或者直接引用该接口,或者耦合到引用该接口的基类。界面。


迫切需要一种确保复古兼容性的方法,因此这是您的第一个挑战。隔离用于单元测试的组件。

请记住,假定现有代码的可能结果而制作了那25k行代码。如果您不违反合同的这一部分,那么最终解决方案就已经完成了一半。如果您这样做,那么:力量可能与您同在吗?

设计并实施新的“合同”后,请替换旧的。弃用或取出。

我建议不要将bug保留下来,因为重构和修复bug是不同的任务。如果您尝试将它们一起推进,则可能两者都失败。您可能认为您发现了错误,但是,它们可能是“功能”。因此,让他们一个人呆一分钟。

25k行代码在我看来已经足够多的问题,使我只能专注于一项任务。

一旦完成第一个任务。将这些错误/功能暴露给老板。

最后,就像@Stephen告诉的那样:


除了缓慢地使事情变得更好以外,您无能为力。 。
创建新类时,请确保正确测试它们并
使用SOLID原理创建它们,以便将来更容易更改它们


#9 楼

测试它。

其他所有人都建议如何重构,因此影响不大。但是有这么多错误,即使您仅用10行代码就能成功进行重构(可能也可以),即使您不需要重写它们,也影响了25,000个代码流。

因此,接下来要做的就是确保您的回归测试套件通过测试并获得成功。如果您没有,那就做一个。在您的整体项目中添加全面的回归测试套件听起来很无聊,但这是一种增加对候选发布版本的信心的好方法,并且如果套件自动化良好,则可以更快地发布它们。