13

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

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

实际上,这个系统是如此的破碎,它没有做它需要做的事情。

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

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

那么你将如何着手改进这个系统呢?你会遵循什么策略?

一些额外的事情:我是一个单人军队,因此雇佣足够多的人并重新设计/重构系统是不可接受的答案。在几周或几个月后,我真的应该表现出一些明显的进步,所以在几年内自己进行重构也不是一个选择。

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

附加信息:

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

更新:

我接受了 Greg D 的回答。即使我更喜欢亚当·贝莱尔的作品,也不知道什么是最理想的。谢谢大家的回答。

4

9 回答 9

14
  1. 扑灭大火。如果有任何至关重要的问题,无论它们是什么,你都必须首先处理它们。如果必须的话,用一个臭的代码库就可以了。你知道你会在未来改进它。这是针对您向谁汇报的销售技巧。
  2. 摘一些低垂的果实。 我假设您对这个特定软件相对较新,并且您被重新分配了处理它的任务。在代码的相关子系统中找到一些明显简单的问题,这些问题不应该花费超过一两天的时间来解决,并修复它们。这可能涉及重构,也可能不涉及。目标是熟悉系统和原作者的风格。你可能不会真的很幸运(在我之前在我的系统上工作的两个不称职的人之一总是用四个标点符号而不是一个标点符号来修正他的评论,这使得很容易区分谁编写了特定的代码段。),但是您会深入了解作者的弱点,因此您知道要注意什么。例如,与全局状态的广泛、紧密耦合与对语言工具的理解不足。
  3. 设定一个大目标。 如果您的经验与我的相似,那么当您执行前面的步骤时,您会发现自己越来越频繁地陷入特定的意大利面条代码中。这是您需要解开的第一个结。凭借您对组件的了解以及原始作者可能做错了什么(因此,您需要注意什么)的经验,您可以开始为系统的这个子集设想一个更好的模型。如果您仍然需要维护一些杂乱的界面来维护功能,请不要担心,只需一步一步完成。

起泡,冲洗,重复!:)

给定时间,考虑在与系统其余部分的接口下一层为您的新模型添加单元测试。不要通过使用它们的测试将坏接口刻在代码中,您将在未来的迭代中更改它们。

解决您提到的特定问题:

当您遇到用户手动解决的情况时,请与用户讨论如何更改它。如果您在投入时间之前提供更改,请确认他们会接受更改。如果他们不想要改变,你的工作就是维持不正常的行为。

当您遇到多个其他组件已经解决的错误组件时,我支持并行组件技术。创建一个计数器,它可以按照现有计数器的工作方式工作。提供一个相似的(或者,如果可行的话,相同的)界面并将新组件滑入代码库。当您触摸可以解决损坏的外部组件时,请尝试用新组件替换旧组件。类似的接口简化了代码的移植,如果新组件失败,旧组件仍然存在。在可以之前不要移除旧组件。

于 2008-10-10T18:27:55.313 回答
3

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

如果您没有人力、时间或资源来“修复”整个系统,那么您所能做的就是保释金。你是说你应该能够在几个月的时间内取得一些“明显的进步”。好吧,由于系统如您所描述的那样糟糕,您实际上可能会使系统变得更糟。在做一些引人注目的事情的压力下,您只需添加代码,并使系统更加复杂。

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

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

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

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

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

于 2008-10-10T18:16:12.233 回答
2

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

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

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

于 2008-10-10T18:07:32.377 回答
1

使用 Windows 资源管理器打开包含该系统的目录。然后,按 Ctrl-A,然后按 Shift-Delete。在你的情况下,这听起来像是一个改进。

不过说真的:那个计数器听起来好像有线程安全问题。我会锁定增加的功能。

而对于系统的其余部分,你不能做不可能的事,所以尽量做可能的事。您需要从两个方面攻击您的系统。先处理比较明显的问题,这样你才能显示出进步。同时,您应该处理更多的基础设施问题,以便有一天您有机会真正修复这个问题。

祝你好运,愿源与你同在。

于 2008-10-10T18:05:45.517 回答
1

选择一个重构难度中等的区域。仅使用现有方法签名创建原始代码的骨架;甚至可能使用接口。然后开始破解。您甚至可以将“新”方法指向旧方法,直到找到它们。

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

当你进入某种存储库时,记录你的进展,包括挫折和问题,这样当下一个得到这个项目的可怜的 schmuck 不会是你所在的地方:)。

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

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

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

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

于 2008-10-10T18:05:52.427 回答
1

近三年来,我一直在使用具有相同特征的遗留系统,并且没有我知道的捷径。

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

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

您可能希望通过采访人来尽可能多地记录下来。这是一项艰巨的任务,因为您不知道要问哪些问题,而且人们会忘记很多细节。

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

于 2008-10-10T18:30:51.410 回答
0

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

于 2008-10-10T18:06:52.160 回答
0

我会尝试选择可以相当快地单独提取和重写的系统部分。即使它做的不多,您也可以很快显示进度,并且您不存在直接与遗留代码交互的问题。

希望如果你能挑出一些这样的任务,他们会看到你取得了明显的进步,你可以提出一个论点来雇佣更多的人来重写更大的模块。当系统的某些部分依赖于损坏的行为时,您别无选择,只能在修复任何东西之前分离。

希望您可以逐步建立一个能够重写整个代码的团队。

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

祝你好运!

于 2008-10-10T18:18:21.387 回答
0

弃用当前存在的所有问题,并编写可以正常工作的新问题。尽可能多地记录将发生的变化,并在指向该文档的地方放置大红色闪烁的标志。

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

于 2008-10-10T18:25:51.137 回答