改善真正糟糕的系统

时间:2008-10-10 17:59:15

标签: refactoring system

你会如何开始改善一个非常糟糕的系统?

在您建议创建单元测试和重构之前,让我解释一下我的意思。我可以使用这些技术,但在这种情况下这将毫无意义。

实际上系统太破碎了,它没有做它需要做的事情。

例如,系统应计算它发送的消息数量。它主要起作用,但在某些情况下它会“忘记”增加消息计数器的值。问题是,许多其他具有自己的变通方法的模块建立在这个计数器上,如果我纠正计数器,整个系统将变得比现在更糟。解决方案可能是修改所有模块并删除它们自己的更正,但是有150多个模块需要这么多的协调,我付不起它。

更糟糕的是,有些问题的解决方法并非在系统本身,而是在人们的脑海中。例如,系统不能在一个消息组中表示超过四个相关消息。某些服务需要将五个消息组合在一起。会计部门知道这种限制,每次他们计算这些服务的消息时,他们会计算消息组并将其乘以5/4以获得正确的消息数。绝对没有关于这些偏差的文档,没有人知道现在系统中有多少这样的东西。

那么你将如何开始改进这个系统呢?你会采取什么策略?

还有一些额外的事情:我是一个单人军队,因此雇用足够的人并重新设计/重构系统是不可接受的答案。在几周或几个月内,我真的应该展示一些明显的进展,所以不能选择在几年内进行重构。

一些技术细节:系统是用Java和PHP编写的,但我认为这并不重要。它背后有两个数据库,一个是Oracle和一个PostgreSQL数据库。除了代码本身之前提到的缺陷之外,它的编写和记录也非常糟糕。

其他信息:

计数器问题不是同步问题。 counter ++语句被添加到某些模块中,而不会添加到其他模块中。快速而肮脏的修复是将它们添加到缺失的位置。长期解决方案是使其成为需要它的模块的一个方面,以后不可能忘记它。我没有修复这样的问题,但是如果我做这个改变,我会打破其他10个模块。

更新

我接受了Greg D的回答。即使我更喜欢Adam Bellaire,也不会帮助我知道什么是理想的。谢谢大家的回答。

9 个答案:

答案 0 :(得分:14)

  1. 扑灭火灾。如果存在任何关键优先级问题,无论它们是什么,您都必须先处理它们。如果必须,请将其删除,使用臭臭的代码库就可以了。你知道你会改进它。这是针对您报告的任何人的销售技巧。
  2. 选择一些悬而未决的成果。我认为你对这个特定的软件比较新,并且你被重新负责处理它。在代码的相关子系统中找到一些显然容易出现的问题,这些问题不应该花费一两天的时间来解决,并修复它们。这可能涉及重构,或者可能不涉及。目标是熟悉系统和原作者的风格。你可能不会很幸运(在我之前使用我的系统的两位不称职的人之一总是用四个标点符号而不是一个标点符号来修复他的评论,这使得很容易区分谁编写了特定的代码段。),但是你会深入了解作者的弱点,所以你知道要注意什么。例如,与全球状态的广泛紧密结合与对语言工具的不良理解。
  3. 设定一个大目标。如果您的体验与我的相似,那么当您执行上一步时,您会发现自己处于特定的意大利面条代码中。这是你需要解开的第一个结。根据您的经验,您已经了解了原始作者可能做错的组件和知识(因此,您需要注意什么),您可以开始为系统的这个子集设想更好的模型。如果你仍然需要维护一些凌乱的界面来维护功能,请不要担心,只需一步一步。
  4. 泡沫,冲洗,重复! :)

    考虑到时间,请考虑在接口下方的一个级别为系统的其余部分添加新模型的单元测试。不要通过使用它们的测试在代码中雕刻坏接口,你将在以后的迭代中更改它们。

    解决您提到的特定问题:

    当您遇到用户正在手动解决的情况时,与用户讨论有关更改它的信息。如果您在更改时间之前提供更改,请确认他们将接受更改。如果他们不想要改变,那么你的工作就是保持破碎的行为。

    当您遇到多个其他组件已经解决的错误组件时,我支持并行组件技术。创建一个计数器,该计数器可以处理现有 的工作方式。提供类似的(或者,如果实际的,相同的)接口,并将新组件滑入代码库。当您触摸解决损坏的外部组件时,请尝试使用新组件替换旧组件。类似的接口可以方便地移植代码,如果新的组件出现故障,旧的组件仍然存在。在可以之前不要删除旧组件。

答案 1 :(得分:3)

现在问你什么?您是否被要求实施功能或修复错误?他们甚至知道他们想要你做什么吗?

如果你没有人力,时间或资源来“整理”整个系统,那么你所能做的只是保释水。你说你应该能在几个月后做出一些“明显的进步”。好吧,由于系统和你描述的一样糟糕,你实际上可能会使系统变得更糟。在做一些值得注意的事情的压力下,你只需添加代码,让sysem更加复杂。

你最终需要重构。没有其他办法了。如果您能找到最终用户可以看到的重构方法,那将是理想的,即使需要6-9个月或一年而不是“几个月”。但如果你不能,那么你可以选择:

  • 重构,尽管你付出了努力,但仍被视为“没有完成任何事情”
  • 不要重构,实现“可见”目标,并使系统更复杂,更难以重构一天。 (也许在你找到一份更好的工作之后,希望下一位开发人员找不到你住的地方。)

哪一个对您个人最有利,取决于您公司的文化。他们有一天会决定雇用更多的开发人员,或者用其他产品完全替换这个系统吗?

相反,如果你“解决问题”的努力实际上打破了其他事情,他们会不会理解你被单独要求解决的怪物?

这里没有简单的答案,抱歉。您必须根据您独特的个人情况进行评估。

答案 2 :(得分:2)

这是一本完整的书,基本上会说单元测试和重构,但有更多关于如何做的实用建议

http://ecx.images-amazon.com/images/I/51RCXGPXQ8L._SL500_AA240_.jpg

http://www.amazon.com/Working-Effectively-Legacy-Robert-Martin/dp/0131177052

答案 3 :(得分:1)

使用Windows资源管理器打开包含此系统的目录。然后,按Ctrl-A,然后按Shift-Delete。这听起来像是你案件的改进。

严重的是:该计数器听起来像是有线程安全问题。我会锁定不断增加的功能。

关于系统的其他部分,你不能做不可能的事情,所以尽量做到可能。您需要从两个方面攻击您的系统。首先处理更明显问题的问题,以便显示进度。与此同时,你应该处理更多的基础设施问题,这样你有一天就有可能真正解决这个问题。

祝你好运,也许消息来源与你同在。

答案 4 :(得分:1)

选择一个中等难度的区域进行重构。仅使用现有代码的方法签名创建原始代码的框架;甚至可以使用界面。然后开始乱砍。您甚至可以将“新”方法指向旧方法,直到找到它们为止。

然后,测试,测试,测试。由于没有任何单元测试,可能只是使用老式的语音激活单元测试(人)?或者随时编写自己的测试。

记录您进入某种存储库时的进度,包括挫折和问题,以便当下一个获得此项目的可怜的骗子不在您所在的位置时:)。

完成第一部分后,继续下一部分。关键是要建立在渐进式进步之上,这就是为什么你不应该首先从最难的部分开始;让事情变得士气低落太容易了。

Joel有几篇关于重写/重构的文章:

http://www.joelonsoftware.com/articles/fog0000000069.html

http://www.joelonsoftware.com/articles/fog0000000348.html

答案 5 :(得分:1)

我已经使用具有相同特征的遗留系统近三年了,并且没有我所知道的捷径。

使用我们的遗留系统最让我困扰的是我不允许修复一些错误,因为如果修复它们,许多其他功能可能会破坏。这需要丑陋的解决方法或创建旧版本的旧功能。然后可以一次用新的函数替换对旧函数的调用(在测试时)。

我不确定你的任务的目标是什么,但我强烈建议你尽可能少地触摸代码。只做你需要做的事。

您可能希望通过面试人员记录尽可能多的文件。这是一项艰巨的任务,因为你不知道要问哪些问题,人们会忘记很多细节。

除此之外:确保你获得报酬和足够的道德支持。会有哭泣和咬牙切齿......

答案 6 :(得分:0)

嗯,你需要从某个地方开始,听起来有些错误需要修复。我会解决这些错误,快速获得重构,并在此过程中编写任何单元测试。我还会使用像SourceMonitor这样的工具来识别系统中一些最复杂的代码部分,看看我是否可以以任何方式简化他们的设计。最终,你必须接受这将是一个缓慢的过程,并朝着更好的系统迈出一小步。

答案 7 :(得分:0)

我会尝试选择一部分可以快速提取和重写的系统。即使它没有做太多,你也可以很快地显示进度,并且你没有直接与遗留代码接口的问题。

希望如果你可以选择一些这样的任务,他们会看到你取得明显的进展,你可以提出一个论据,雇用更多的人来重写更大的模块。当系统的某些部分依赖于破坏的行为时,您没有太多选择,只能在修复任何内容之前将其分开。

希望你能逐步建立一支能够改写整个团队的团队。

所有这一切都必须与一些体面的培训齐头并进,否则人们的旧习惯会坚持下去,当事情无法按预期发挥作用时,你的工作将受到责备。

祝你好运!

答案 8 :(得分:0)

弃用当前存在的有问题的所有内容,并编写可正常工作的新内容。尽可能多地记录有关改变的内容,并在指向本文档的地方放置大红色闪烁标志。

通过这样做,您可以保持现有的错误(那些正在被其他地方补偿的错误),而不会减慢您获得实际工作系统的进度。